【BZOJ】2565: 最长双回文串

【题意】给定小写字母字符串s,求最长的 [ 可以分成左右两个回文串的 ] 子串,n<=10^5。

【算法】回文树

【题解】对于每个字符x,处理出以x结尾的最长回文串,以x开头的最长回文串,然后枚举中间点求解。

只须正反用两次回文树就可以处理完毕。

#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;
}
View Code
原文地址:https://www.cnblogs.com/onioncyc/p/8017785.html