BZOJ 2565 最长双回文串(manacher)
565: 最长双回文串
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 3343 Solved: 1692
[Submit][Status][Discuss]
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
HINT
样例说明
从第二个字符开始的字符串aacaabbacabb可分为aacaa与bbacabb两部分,且两者都是回文串。
对于100%的数据,2≤|S|≤10^5
题解
先跑一遍manacher,然后对于每一个点求出左边和右边最远可以包含它的回文串的中心。
然后枚举每一个‘#’求这种点右边回文中心与左边回文中心的差的最大值即可。
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<cstdio> 5 #include<algorithm> 6 using namespace std; 7 const int N=300001; 8 char str[N],s[N]; 9 int len,p[N],l[N],r[N],ans,m; 10 void init(){ 11 str[0]=str[1]='#'; 12 for(int i=1;i<=len;i++){ 13 str[len<<1]=s[i]; 14 str[(len<<1)+1]='#'; 15 } 16 m=len*2+1; 17 } 18 void manacher(){ 19 int mx=0,id; 20 for(int i=1;i<=m;i++){ 21 if(mx>i)p[i]=min(p[id-(i-id)],mx-i+1); 22 else p[i]=1; 23 while(str[i-p[i]]==str[i+p[i]])p[i]++; 24 if(i+p[i]-1>mx){ 25 mx=i+p[i]-1; 26 id=i; 27 } 28 } 29 } 30 int main(){ 31 scanf("%s",s+1); 32 len=strlen(s+1); 33 init(); 34 manacher(); 35 int mx=1; 36 for(int i=1;i<=m;i++) 37 for(;mx<=i+p[i]-1;mx++)l[mx]=i; 38 int mn=m; 39 for(int i=m;i>=1;i--) 40 for(;mn>=i-p[i]+1;mn--)r[mn]=i; 41 for(int i=1;i<=len;i++){ 42 ans=max(ans,r[i*2]-l[i*2]); 43 } 44 printf("%d",ans); 45 return 0; 46 }