Time Limit: 10 Sec Memory Limit: 128 MB
Description
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为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
Solution
还算是比较板的一道题吧……manacher和回文自动机都能做,这里介绍回文自动机的解法。
很多字符串题目的难点与关键点在于把字符串进行变化。设
l[i]
l
[
i
]
为以
s[i]
s
[
i
]
为最后一个字符的最长回文串长度,
r[i]
r
[
i
]
为以
s[i]
s
[
i
]
开头的最长回文串长度,题目要求的即为
max(l[i]+r[i+1])
m
a
x
(
l
[
i
]
+
r
[
i
+
1
]
)
。回文自动机只能求到
l[i]
l
[
i
]
,我们需把
s
s
翻转再建一个机子才能得到。
Code
#include<stdio.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=1e5+5;
int n,ans,pos,tot,Last,l[maxn],r[maxn],sa[maxn],len[maxn],Next[maxn][26];
char s[maxn];
void init()
{
tot=Last=2,len[1]=-1;
sa[1]=sa[2]=1;
}
int match(int x)
{
while(s[pos]!=s[pos-len[x]-1]) x=sa[x];
return x;
}
void insert(char c)
{
int p=match(Last),t=c-'a';
if(Next[p][t])
{
Last=Next[p][t];
if(!l[pos]) l[pos]=len[Last];
else r[n-pos+1]=len[Last];
return;
}
Last=++tot,Next[p][t]=tot,len[tot]=len[p]+2;
if(!l[pos]) l[pos]=len[tot];
else r[n-pos+1]=len[tot];
if(len[tot]==1){sa[tot]=2;return;}
p=match(sa[p]),sa[tot]=Next[p][t];
}
int main()
{
scanf("%s",s+1),n=strlen(s+1),init();
for(pos=1;pos<=n;pos++) insert(s[pos]);
reverse(s+1,s+1+n),memset(Next,0,sizeof(Next));
memset(len,0,sizeof(len)),memset(sa,0,sizeof(sa)),init();
for(pos=1;pos<=n;pos++) insert(s[pos]);
for(int i=1;i<n;i++) ans=max(ans,l[i]+r[i+1]);
printf("%d\n",ans);
return 0;
}