CF 119D String Transformation 题解
emm不知道为啥会评黑……其实不难(虽然看了题解才想起来有哈希这玩意)。
题目给了一种翻转操作,乍一看无从下手,但是如果你画一画示意图,会发现很多东西。
如图,我们用箭头表示方向,颜色表示三个不同的部分。这样看的话,我们发现,标号为
这时候,让我们把原串
但是,还没完。这里有个正确性的问题,那就是,我们处理出极长字串是否正确。为什么这样说?因为我们发现,题目要求 (才不是因为我懒呢)。
代码:
#include<bits/stdc++.h> #define ll long long using namespace std; const int N = 1e6+100; const int pa = 23, pb = 233, ma = 998244353, mb = 1000000007; int n; ll hasha[2][N], hashb[2][N], spa[N], spb[N], hashc[N]; char s[N], fs[N]; char t[N]; int nxt2[N], nxt1[N]; int ansl = -1, ansr = -1; void init(){ spa[0] = spb[0] = 1; for(int i = 1; i<=n; i++){ hasha[0][i] = (hasha[0][i-1]*pa%ma+s[i])%ma; hasha[1][i] = (hasha[1][i-1]*pa%ma+t[i])%ma; hashc[i] = (hashc[i-1]*pa%ma+fs[i])%ma; spa[i] = spa[i-1]*pa%ma; } for(int i = 1; i<=n; i++){ hashb[0][i] = (hashb[0][i-1]*pb%mb+s[i])%mb; hashb[1][i] = (hashb[1][i-1]*pb%mb+t[i])%mb; spb[i] = spb[i-1]*pb%mb; } } void check(int l, int r){ if(ansl<l){ ansl = l, ansr = r; }else if(ansl == l&&ansr>r){ ansr = r; } } inline ll geta(int l, int r, int op){ return ((hasha[op][r]-hasha[op][l-1]*spa[r-l+1]%ma)%ma+ma)%ma; } inline ll getb(int l, int r, int op){ return ((hashb[op][r]-hashb[op][l-1]*spb[r-l+1]%mb)%mb+mb)%mb; } inline ll getc(int l, int r){ return ((hashc[r]-hashc[l-1]*spa[r-l+1]%ma)%ma+ma)%ma; } void KMP(){ int j = 0; for(int i = 2; i<=n; i++){ while(j&&fs[j+1]!=fs[i]){ j = nxt1[j]; } if(fs[j+1] == fs[i])++j; nxt1[i] = j; } j = 0; for(int i = 1; i<=n; i++){ while(j&&fs[j+1]!=t[i]){ j = nxt1[j]; } if(fs[j+1] == t[i]) j++; nxt2[i] = j;//求出1号串左端的极大位置。 } for(int i = 1; i<n; i++){ int pos = nxt2[i]; if(!pos) continue; if(geta(i+1, n, 1) == getc(i+1, n)&&geta(1,i-pos, 1)==geta(n-i+1, n-pos, 0)&&getb(1,i-pos, 1)==getb(n-i+1, n-pos, 0)){ check(n-i-1, n-pos); } } } int main(){ cin.getline(s+1, 1000006); cin.getline(t+1, 1000006); n = strlen(s+1); int mtp = strlen(t+1); if(n ^ mtp){ puts("-1 -1"); return 0; } for(int i = 1; i<=n; i++){ fs[i] = s[n-i+1]; } init(); KMP(); printf("%d %d\n", ansl, ansr); return 0; }