LightOJ 1258 Making Huge Palindromes(KMP)
阿新 • • 發佈:2019-01-01
題意
給定一個字串 \(S\) ,一次操作可以在這個字串的右邊增加任意一個字元。求操作之後的最短字串,滿足操作結束後的字串是迴文。
\(1 \leq |S| \leq 10^6\)
思路
\(\text{KMP}\) 的 \(fail\) 陣列是整個演算法最重要的東西,能拓展出很多東西。
對於一個模式串(pattern)\(P\) ,\(fail\) 陣列為 \(f\) ,那麼 \(f[i]\) 就是如果匹配到 \(i\) 這個位置失配,下次去嘗試的位置,也就說明了從字串頭到 \(f[i]-1\) 這一段,在 \(i-1\) 位置以左有一段相同的串。這是對 \(fail\) 陣列的一種理解,想要更深入的理解,最好的方法就是做題。
本題等價於在 \(S\) 左邊刪去任意字元使剩下的字串迴文,只需求出字串 \(S\) 從右開始能得到最長的迴文串長度即可。設模式串為 \(S\) 的反字串 \(P\),迴文串長度就是 \(S\) 在最右端能匹配 \(P\) 的最長長度。
程式碼
#include<bits/stdc++.h> #define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i) #define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i) typedef long long LL; using namespace std; const int N=1e6+5; char T[N],P[N]; int n,f[N]; int main() { int Case; scanf("%d",&Case); FOR(cas,1,Case) { scanf("%s",T); n=strlen(T); FOR(i,0,n-1)P[i]=T[n-i-1]; P[n]='\0'; f[0]=f[1]=0; FOR(i,1,n-1) { int j=f[i]; while(j&&P[i]!=P[j])j=f[j]; f[i+1]=j+(P[i]==P[j]); } int j=0; FOR(i,0,n-1) { while(j&&T[i]!=P[j])j=f[j]; if(T[i]==P[j])j++; if(i==n-1)printf("Case %d: %d\n",cas,n+(n-j)); } } return 0; }