题目链接->传送门
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
思路:马拉车填充后求出每个字符的回文半径,在枚举所有的#,找以此#为中心最左和最右的回文串长度,这里分别用l[i]和r[i]表示,i是小回文串的中心,双回文串长度恰好等于l[i]+r[i]。
贴代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<set> #include<map> #define N 100005 using namespace std; int p[N<<1],l[N<<1],r[N<<1]; char s[N],t[N<<1]; int main() { scanf("%s",s); int len=strlen(s); int i; for(i=1; i<=len; i++) t[2*i]=s[i-1],t[2*i+1]='#'; t[0]='!',t[1]='#'; t[2*len+2]='\0'; len=2*len+1; int mx=0,id=0,ans=0; for(i=1; i<=len; i++) { if(mx>i) p[i]=min(p[2*id-i],mx-i); else p[i]=1; while(t[i+p[i]]==t[i-p[i]]) p[i]++; if(mx<i+p[i]) mx=i+p[i],id=i; } i=1; for(id=3; id<=len-2; id+=2)//#为分割点枚举 { for(; i<=len; i++)//i不用从头开始循环,否则超时 { if(i+p[i]-1>=id)//小回文串回文半径大于枚举中心才行 { l[id]=i;//以id为结尾的最左边字符串中心为i break;//跳出,分割点右移,因为如果再让i增加就不是最左的回文串了 } } } i=len; for(id=len-2; id>=3; id-=2) { for(; i>=1; i--) { if(i-(p[i]-1)<=id) { r[id]=i; break; } } } for(id=3; id<=len-2; id++) ans=max(ans,r[id]-l[id]); printf("%d\n",ans); return 0; }