【BZOJ】2565: 最长双回文串
【题意】给定小写字母字符串s,求最长的 [ 可以分成左右两个回文串的 ] 子串,n<=10^5。
【算法】回文树
【题解】对于每个字符x,处理出以x结尾的最长回文串,以x开头的最长回文串,然后枚举中间点求解。
只须正反用两次回文树就可以处理完毕。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int maxn=100010; int length,sz,nownode,n,fail[maxn],len[maxn],ch[maxn][30],a[maxn],b[maxn]; char s[maxn]; int getfail(int x){while(s[length-len[x]-1]!=s[length])x=fail[x];return x;} void insert(int a[]){ int c=s[++length]-'a'; int x=getfail(nownode); while(!ch[x][c]){ len[++sz]=len[x]+2; fail[sz]=ch[getfail(fail[x])][c]; ch[x][c]=sz; } nownode=ch[x][c]; a[length]=len[nownode]; } int main(){ scanf("%s",s+1); n=strlen(s+1); len[0]=0;fail[0]=1; len[1]=-1;fail[1]=1; length=0; sz=1;//important! for(int i=1;i<=n;i++)insert(a); len[0]=0;fail[0]=1; len[1]=-1;fail[1]=1; length=0; sz=1;// for(int i=1;i<=n/2;i++)swap(s[i],s[n-i+1]); for(int i=1;i<=n;i++)insert(b); int ans=0; for(int i=0;i<=n;i++)ans=max(ans,a[i]+b[n-i]); printf("%d",ans); return 0; }