BZOJ2565: 最长双回文串(Manacher)
Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
Input
一行由小写英文字母组成的字符串S。
Output
一行一个整数,表示最长双回文子串的长度。
Sample Input
baacaabbacabb
Sample Output
12
解题思路:
是求两个回文串相加的双回文最大长度。
一直在想两个回文串相交的情况,结果发现是不存在的,那样只会形成更大的一个回文串,蒟蒻就是蒟蒻
记录最右点和最左点。
注意更新!!
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using std::min; 5 using std::max; 6 char a[1000000]; 7 int l[1000000]; 8 int ls[1000000]; 9 int rs[1000000]; 10 int f[1000000]; 11 int ans; 12 int cnt; 13 int main() 14 { 15 scanf("%s",a+1); 16 int len=strlen(a+1); 17 l[cnt]='&'; 18 for(int i=1;i<=len;i++) 19 { 20 l[++cnt]='&'; 21 l[++cnt]=a[i]; 22 } 23 l[++cnt]='&'; 24 int mx=1; 25 f[1]=1; 26 for(int i=2;i<=cnt;i++) 27 { 28 f[i]=min(f[mx*2-i],f[mx]+mx-i); 29 while(f[i]+i<=cnt&&l[f[i]+i]==l[i-f[i]]) 30 f[i]++; 31 if(mx+f[mx]<i+f[i]) 32 mx=i; 33 rs[f[i]+i-1]=max(rs[f[i]+i-1],f[i]-1); 34 ls[i-f[i]+1]=max(ls[i-f[i]+1],f[i]-1); 35 } 36 for(int i=1;i<=cnt;i+=2) 37 ls[i]=max(ls[i],ls[i-2]-2); 38 for(int i=cnt;i>=1;i-=2) 39 rs[i]=max(rs[i],rs[i+2]-2); 40 for(int i=1;i<=cnt;i+=2) 41 ans=max(ans,rs[i]+ls[i]); 42 printf("%d\n",ans); 43 return 0; 44 }