题目
顺序和逆序读起来完全一样的串叫做回文串。比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同)。
输入长度为n的串S,求S的最长双回文子串T,即可将T分为两部分X,Y,(|X|,|Y|≥1)且X和Y都是回文串。
分析
先把串S正着做一次回文自动机
得到数组len_pro
len_pro[i]表示以S[i]结尾的最长回文子串
接着把串S反着做一次回文自动机
得到数组len_nex
len_nex[i]表示从S[i]开始的最长回文子串
然后枚举分割点即可
code
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<string>
#include<algorithm>
#define maxn 500005
#define maxm 600005
#define INF 0x7fffffff;
using namespace std;
int next[maxn][30],fail[maxn],len[maxn],num[maxn];
int mx1[maxn],mx2[maxn];
long long cnt[maxn];
int S[maxn];
int last;
int N=0;
int p=0;
void newnode(int l)
{
++p;
for (int i=1;i<=26;i++) next[p][i]=0;
len[p]=l;
num[p]=0;
cnt[p]=0;
}
int get_fail(int x)
{
while (S[N-len[x]-1]!=S[N]) x=fail[x];
return x;
}
void add(char C)
{
int c=C-'a'+1;
S[++N]=c;
int cur=get_fail(last);
if (!next[cur][c])
{
newnode(len[cur]+2);
fail[p]=next[get_fail(fail[cur])][c];
next[cur][c]=p;
num[p]=num[fail[p]]+1;
}
last=next[cur][c];
mx1[N]=len[last];
cnt[last]++;
}
void count()
{
for (int i=p;i>=0;i--) cnt[fail[i]]+=cnt[i] ;
}
int main()
{
string s;
cin>>s;
p=-1;
newnode(0);
newnode(-1);
last=0; N=0;
S[N]=-1; fail[0]=1;
for (int i=0;i<s.length();i++)
{
add(s[i]);
mx2[i+1]=mx1[i+1];
}
count();
memset(next,0,sizeof(next));
memset(fail,0,sizeof(fail));
memset(len,0,sizeof(len));
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
memset(mx1,0,sizeof(mx1));
memset(S,0,sizeof(S));
p=-1;
newnode(0);
newnode(-1);
last=0; N=0;
S[N]=-1; fail[0]=1;
for (int i=s.length()-1;i>=0;i--)
{
add(s[i]);
}
int ans=0;
for (int i=1;i<=s.length();i++)
{
int k=mx2[i]+mx1[s.length()-(i+1)+1];
if (k>ans) ans=k;
}
cout<<ans;
}