题意
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
2≤|S|≤10^5
分析
直接用manachar求出f[i]表示以i为结尾的最长回文串,g[i]表示以i为开头的最长回文串,然后扫一遍即可。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=200005;
int n,w[N],f[N],a[N],g[N],len[N];
char s[N];
void manachar()
{
for (int i=1;i<=n;i++) a[i*2]=s[i]-'a',a[i*2-1]=30;
a[n*2+1]=30;
int mx=0,pos=0;
for (int i=1;i<=n*2+1;i++)
{
if (mx>=i) len[i]=min(mx-i+1,len[pos*2-i]);
else len[i]=1;
while (i-len[i]>0&&i+len[i]<=n*2+1&&a[i-len[i]]==a[i+len[i]])
{
len[i]++;
if (i+len[i]-1>mx) w[i+len[i]-1]=len[i]*2-1;
}
if (i+len[i]-1>mx) mx=i+len[i]-1,pos=i;
}
}
int main()
{
scanf("%s",s+1);
n=strlen(s+1);
manachar();
for (int i=1;i<=n;i++) f[i]=w[i*2+1]/2;
for (int i=1;i<=n/2;i++) swap(s[i],s[n-i+1]);
manachar();
for (int i=1;i<=n;i++) g[n-i+1]=w[i*2+1]/2;
int ans=0;
for (int i=1;i<n;i++) ans=max(ans,f[i]+g[i+1]);
printf("%d",ans);
return 0;
}