今天思维性差了一点,但是我的失误变得贼多...
T1:https://www.luogu.org/problem/T92371
失误:我 竟然 没看见 多组数据
爆零彻底
找规律题,答案是n * phi[n] / 2
证明:
集合{[0,n-1]中存在逆元的数}==集合{[0,n-1]中存在逆元的数的逆元}
gcd(n,i)=gcd(n,n-i);
所以与n互质的数可以关于n/2对称的,也就是相加等于n;
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<vector> #include<cmath> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); typedef int mainint; #define int long long inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } int n; const int maxn = 2e5 + 5; int p[maxn],cnt; bool vis[maxn]; void init(int n) { for(int i = 2;i <= n;i++) { if(!vis[i]) p[++cnt] = i; for(int j = 1;j <= cnt && i * p[j] <= n;j++) { vis[i * p[j]] = 1; if(i % p[j] == 0) break; } } } int gcd(int a,int b) { return !b ? a :gcd(b,a % b); } mainint main() { freopen("zip.in","r",stdin); freopen("zip.out","w",stdout); int t = read(); while(t--) { int n = read(); int N = maxn - 5; init(N); int tot = 1,tp = n; for(int i = 2;i <= sqrt(n);i++) { if(tp % i == 0) tp /= i,tot *= (i - 1); while(tp % i == 0) tp /= i,tot *= i; } if(tp != 1) tot *= (tp - 1); printf("%lld ",tot * n / 2); } return 0; }
T2:https://www.luogu.org/problem/T92372
失误:处理第二问时,我直接向下dfs,这样复杂度会炸
1,3问略
第二问:记录F[u][0]/[1]:u不选/选,除u及其子树以外的点的最小花费
转移:
F[u][0] = F[fa][1] + f[fa] - min(f[u],g[u]);
F[u][1] = min(F[u][0],F[fa][0] + g[fa] - f[u]);
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<vector> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); typedef long long ll; inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int maxn = 1e5 + 5; const ll mod = 5462617; int f[maxn],g[maxn],n; ll cntf[maxn],cntg[maxn]; struct egde { int to,next; }e[maxn << 1]; int fir[maxn],alloc; void adde(int u,int v) { e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; swap(u,v); e[++alloc].next = fir[u]; fir[u] = alloc; e[alloc].to = v; } void dfs(int u,int fa) { f[u] = 1,g[u] = 0; cntf[u] = cntg[u] = 1ll; for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(v == fa) continue; dfs(v,u); f[u] += min(f[v],g[v]); if(f[v] < g[v]) (cntf[u] *= cntf[v]) %= mod; else if(f[v] > g[v]) (cntf[u] *= cntg[v]) %= mod; else cntf[u] = cntf[u] * ((cntf[v] + cntg[v]) % mod) % mod; g[u] += f[v],(cntg[u] *= cntf[v]) %= mod; } } bool not_in[maxn]; int F[maxn][2];//0:x不选 1:x选 除x及其子树以外的最大价值 void deal(int u,int fa) { if(u != 1) { F[u][0] = F[fa][1] + f[fa] - min(f[u],g[u]); F[u][1] = min(F[u][0],F[fa][0] + g[fa] - f[u]); } for(int i = fir[u];i;i = e[i].next) { int v = e[i].to; if(v == fa) continue; deal(v,u); } } int main() { freopen("rainbow.in","r",stdin); freopen("rainbow.out","w",stdout); n = read(); for(int i = 1;i < n;i++) { int u = read(),v = read(); adde(u,v); } dfs(1,0); int ans = min(f[1],g[1]); printf("%d ",ans); for(int i = 1;i <= n;i++) not_in[i] = 1; deal(1,0); int cnt = 0; for(int i = 1;i <= n;i++) if(F[i][1] + f[i] != ans) cnt++; printf("%d ",cnt); if(f[1] > g[1]) printf("%lld",cntg[1]); else if(f[1] < g[1]) printf("%lld",cntf[1]); else printf("%lld",(cntf[1] + cntg[1]) % mod); return 0; } /* 5 1 2 1 3 2 4 2 5 */
T3:https://www.luogu.org/problem/T92373
失误:二分时存在可能没有LCP的情况,所以要l=0,r = min(len[x],len[y])
二分+哈希
基数记得选>5e5的
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<climits> #include<map> #include<queue> #include<vector> using namespace std; #define O(x) cout << #x << " " << x << endl; #define B cout << "breakpoint" << endl; #define clr(a) memset(a,0,sizeof(a)); typedef int mainint; #define int long long inline int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') op = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (ans *= 10) += ch - '0'; ch = getchar(); } return ans * op; } const int mod1 = 1e9 + 7; const int mod2 = 998244353; const int b1 = 5e5 + 9; const int b2 = 5e5 + 29; const int maxn = 1e5 + 5; vector<int> hs1[maxn],hs2[maxn]; vector<int> tp[maxn]; int t[maxn * 5],cnt; int n,m,len[maxn],x,y; inline bool check(int s) { return hs1[x][s - 1] == hs1[y][s - 1] && hs2[x][s - 1] == hs2[y][s - 1]; } main() { freopen("girls.in","r",stdin); freopen("girls.out","w",stdout); n = read(),m = read(); for(int i = 1;i <= n;i++) { len[i] = read(); for(int j = 1;j <= len[i];j++) { int x = read(); tp[i].push_back(x); t[++cnt] = x; } } sort(t + 1,t + 1 + cnt); int tot = unique(t + 1,t + 1 + cnt) - t - 1; for(int i = 1;i <= n;i++) { for(int j = 0;j < len[i];j++) { tp[i][j] = lower_bound(t + 1,t + 1 + tot,tp[i][j]) - t + 1; if(j) hs1[i].push_back((hs1[i][j - 1] * b1 % mod1 + tp[i][j]) % mod1), hs2[i].push_back((hs2[i][j - 1] * b2 % mod2 + tp[i][j]) % mod2); else hs1[i].push_back(tp[i][j]),hs2[i].push_back(tp[i][j]); } } while(m--) { x = read(),y = read(); int l = 0,r = min(len[x],len[y]); bool flag = 0; while(l < r) { int mid = (l + r + 1) >> 1; if(check(mid)) l = mid,flag = 1; else r = mid - 1; } printf("%lld ",l); } } /* 3 3 3 1 2 3 3 1 2 4 5 1 2 3 4 5 1 3 2 1 2 3 */
自以为能够AK结果死的很惨。。。
以后要更小心,看题面,多考虑情况,自以为对的题也要对拍一下