BZOJ2342:[SHOI2011]双倍回文(Manacher)
Description
Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
ggabaabaabaaball
Sample Output
12
HINT
N<=500000
Solution
假设manacher过程中求到了位置i
那么我们从i位置一步一步往左右扩张求len[i]的时候
扩张过程中经历的串一定是回文串,只需要判断这些串的左半边是否回文然后更新答案即可。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (1000000+1000) 5 using namespace std; 6 7 int n,tot,len[N]; 8 char a[N],s[N]; 9 10 void Manacher() 11 { 12 int x,mid=0,maxn=0,ans=0; 13 for (int i=1; i<=tot; ++i) 14 { 15 if (i>maxn) x=1; 16 else x=min(maxn-i+1,len[mid*2-i]); 17 while (s[i+x]==s[i-x]) 18 { 19 ++x; 20 if (s[i]=='#' && x%4==1 && len[i-x/2]>=x/2) 21 ans=max(ans,x-1); 22 } 23 len[i]=x; 24 if (i+x-1>maxn) maxn=i+x-1,mid=i; 25 } 26 printf("%d",ans); 27 } 28 29 int main() 30 { 31 scanf("%d%s",&n,a); 32 33 s[++tot]='@'; s[++tot]='#'; 34 for (int i=0; i<n; ++i) 35 s[++tot]=a[i], s[++tot]='#'; 36 s[++tot]='$'; 37 Manacher(); 38 }