这次应该叫高二上一调
A.匹配
我神奇的从火星人profix里获得了搞一个hash后缀数组的灵感,这样就可以直接对应了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; const int maxn = 2e5 + 3; const int N = 1e5 + 3; int T, la, lb; ull p[maxn], ha[maxn], hb[maxn]; char s[maxn], d[2]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); p[0] = 1; for(int i=1; i<=N; i++) { p[i] = p[i-1] * 233; } while(T--) { la = read(); lb = read(); scanf("%s", s+1); scanf("%s", d); memset(ha, 0, sizeof(ha)); memset(hb, 0, sizeof(hb)); for(int i=1; i<=la; i++) { ha[i] = ha[i-1] * 233 + (s[i]-'a'+1); } hb[lb+1] = d[0] - 'a' + 1; for(int i=lb; i>=1; i--) { hb[i] = hb[i+1] + (s[i]-'a'+1) * p[lb-i+1]; } int n = min(la, lb+1), ans = 0; for(int i=n; i>=1; i--) { if(s[i] == d[0]) { if(i == 1) { ans = 1; break; } if(s[lb+2-i] == s[1]) { if(ha[i] == hb[lb+2-i]) { ans = max(ans, i); break; } } } } printf("%d\n", ans); } return 0; }
B.回家
本来打算先找完割点,再从n点dfs一下到1停止找到在路径上的点,最后两个都满足就是答案。
少了一种情况:5 5
1 3
1 2
3 4
3 5
2 5
不是所有既在路径上又是割点的点就是从1到n路径上的割点。能把一个点判定为另一个点一定要在路径上。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const int N = 4e6 + 3; int T, n, m, dfn[maxn], cnt, num; bool iscut[maxn], acc[maxn]; struct node { int next, to; }a[N]; int head[maxn], len; void In(int x, int y) { a[++len].to = y; a[len].next = head[x]; head[x] = len; } inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } /*int dfs(int u, int f) { int lowu = dfn[u] = ++dfs_c; for(int i=head[u]; i; i=a[i].next) { int v = a[i].to; if(v == f) continue; if(!dfn[v]) { int lowv = dfs(v, u); lowu = min(lowu, lowv); if(lowv >= dfn[u] && acc[v]) { iscut[u] = true; } } else { lowu = min(dfn[v], lowu); } acc[u] |= acc[v]; } return lowu; }*/ int low[maxn]; void tarjan(int x, int fa) { //v[x] = true; dfn[x] = low[x] = ++num; bool first = true; int son = 0; for(int i=head[x]; i; i=a[i].next) { int to = a[i].to; if(first && to == fa) { first = false; continue; } if(!dfn[to]) { son++; tarjan(to, x); low[x] = min(low[x], low[to]); if(dfn[x] <= low[to] && acc[to]) { iscut[x] = true; } } else { low[x] = min(low[x], dfn[to]); } acc[x] |= acc[to]; } } void solve() { acc[n] = true; tarjan(1, 0); for(int i=2; i<n; i++) { if(iscut[i]) cnt++; } printf("%d\n", cnt); for(int i=2; i<n; i++) { if(iscut[i]) { printf("%d ", i); } } printf("\n"); } void clear() { num = len = cnt = 0; memset(head, 0, sizeof(head)); memset(dfn, 0, sizeof(dfn)); memset(acc, false, sizeof(acc)); memset(iscut, 0, sizeof(iscut)); } int main() { T = read(); while(T--) { clear(); n = read(); m = read(); for(int i=1; i<=m; i++) { int x = read(), y = read(); In(x, y); In(y, x); } solve(); } return 0; }
C.寿司
1.可以枚举一个中心点让左边的点和右边的点向它靠拢,交换次数就是坐标的差再减去中间相同颜色的点数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const int N = 4e6 + 3; const int INF = 0x3f3f3f3f; int T, len; char s[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); while(T--) { scanf("%s", s); len = strlen(s); int ans = INF; for(int i=0; i<len; i++) { int sum = 0; int nowl = i, cntl = 0, nowr = i, cntr = 0; for(int j=1; j<=(len+1)/2-1; j++) { nowl--; int now = nowl; if(now < 0) { now = (now + len) % len; } if(s[now] == s[i]) { cntl++; sum += i-nowl-cntl; } } for(int j=1; j<=(len+1)/2-1; j++) { nowr++; int now = nowr; if(now >= len) { now %= len; } if(s[now] == s[i]) { cntr++; sum += nowr-i-cntr; } } if(!(len&1)) { if(s[i] == s[(i+len/2)%len]) { if(cntl > cntr) { cntl++; sum += len/2-cntl; } else { cntr++; sum += len/2-cntr; } } } if(sum < ans) { ans = sum; } } printf("%d\n", ans); } return 0; }
2.比较神奇的预处理,但我怀疑这个诡异的下标是题解写复杂了。可以提前把每个格子当中心点需要移动的次数记录下来,找到一个可以推出它旁边的,然后就可以直接用了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e6 + 3; const int N = 4e6 + 3; const ll INF = 1e17; int T, len, a[maxn]; ll f[2][2][maxn], cnt[2][2][maxn]; char s[maxn]; inline int read() { int x = 0, f = 1; char ch = getchar(); while(ch > '9' || ch < '0') { if(ch == '-') { f = -1; } ch = getchar(); } while(ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch^48); ch = getchar(); } return x * f; } int main() { T = read(); while(T--) { memset(f, 0, sizeof(f)); memset(cnt, 0, sizeof(cnt)); scanf("%s", s); len = strlen(s); for(int i=0; i<len; i++) { if(s[i] == 'R') a[i] = 0; else a[i] = 1; } ll ans = INF; for(int i=0; i<=(len+1)/2-2; i++) { cnt[0][a[i]][0]++; f[0][a[i]][0] += i-cnt[0][a[i]][0]+1; } for(int i=1; i<=len; i++) { cnt[0][0][i] = cnt[0][0][i-1]; cnt[0][1][i] = cnt[0][1][i-1]; cnt[0][a[i-1]][i]--; f[0][0][i] = f[0][0][i-1]; f[0][1][i] = f[0][1][i-1]; f[0][1-a[i-1]][i] -= cnt[0][1-a[i-1]][i]; cnt[0][a[(i+(len+1)/2-2)%len]][i]++; f[0][a[(i+(len+1)/2-2)%len]][i] += (len+1)/2-1-cnt[0][a[(i+(len+1)/2-2)%len]][i]; } for(int i=len-1; i>=len-(len-1)/2; i--) { cnt[1][a[i]][len-1]++; f[1][a[i]][len-1] += len-i-cnt[1][a[i]][len-1]; } for(int i=len-2; i>=0; i--) { cnt[1][0][i] = cnt[1][0][i+1]; cnt[1][1][i] = cnt[1][1][i+1]; cnt[1][a[i+1]][i]--; f[1][0][i] = f[1][0][i+1]; f[1][1][i] = f[1][1][i+1]; f[1][1-a[i+1]][i] -= cnt[1][1-a[i+1]][i]; cnt[1][a[(i-(len+1)/2+2+len)%len]][i]++; f[1][a[(i-(len+1)/2+2+len)%len]][i] += (len+1)/2-1-cnt[1][a[(i-(len+1)/2+2+len)%len]][i]; } for(int i=0; i<len; i++) { ll sum = f[0][a[i]][(i+1)%len]+f[1][a[i]][(i-1+len)%len]; if(!(len&1)) { if(a[i] == a[(i+len/2)%len]) { if(cnt[0][a[i]][(i+1)%len] > cnt[1][a[i]][(i-1+len)%len]) { sum += len/2-cnt[0][a[i]][(i+1)%len]; } else { sum += len/2-cnt[1][a[i]][(i-1+len)%len]; } } } if(sum < ans) { ans = sum; } } printf("%lld\n", ans); } return 0; }
3.好像有更快的方法,等我去研究一下……
其实就是方法一的式子化简一下,其中有一个部分可以用等差数列求和公式,Nothing else~
改天再更新代码。。更新也是抄的。。
时光花火,水月星辰