bzoj2342 [Shoi2011]双倍回文

建立回文树得出所有本质不同的回文串,用hash判断每个长度为偶数的回文串其双倍是否是原串的子串

#include<cstdio>
#include<algorithm>
typedef unsigned long long u64;
const int N=500005,P=293;
u64 pp[N]={1},h[N],hs[N];
int nx[N][26],fa[N],l[N],t[N],d[N],q[N],ql=0,qr=0,ptr=2,pv=2,len;
char s[N];
void ins(int w){
    int p=pv,x,c=s[w]-'a';
    while(1){
        x=w-1-l[p];
        if(x>=0&&s[w]==s[x])break;
        p=fa[p];
    }
    if(nx[p][c]){
        pv=nx[p][c];
        return;
    }
    pv=++ptr;
    l[pv]=l[p]+2;
    nx[p][c]=pv;
    if(!(l[pv]&1))h[pv]=h[p]*P+s[w]+s[w]*pp[l[pv]-1];
    if(l[pv]==1){
        fa[pv]=2;
        return;
    }
    while(1){
        p=fa[p];
        x=w-1-l[p];
        if(x>=0&&s[w]==s[x]){
            fa[pv]=nx[p][c];
            break;
        }
    }
}
int main(){
    l[1]=-1;
    fa[1]=fa[2]=1;
    scanf("%d%s",&len,s);
    for(int i=1;i<=len;i++)pp[i]=pp[i-1]*P;
    for(int i=0;i<len;i++)ins(i);
    for(int i=3;i<=ptr;i++)hs[i]=h[i];
    std::sort(hs+3,hs+ptr+1);
    int ans=0;
    for(int i=3;i<=ptr;i++){
        if(l[i]&1)continue;
        if(l[i]<ans)continue;
        u64 v=h[i]*pp[l[i]]+h[i];
        if(*std::lower_bound(hs+3,hs+ptr+1,v)==v)ans=l[i];
    }
    printf("%d",ans*2);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5493789.html