首页 > 代码库 > bzoj2342 [Shoi2011]双倍回文

bzoj2342 [Shoi2011]双倍回文

Description

技术分享

Input

输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。

Output

输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。

Sample Input

16
ggabaabaabaaball

Sample Output

12

HINT

N<=500000

 

正解:回文自动机。

一道回文自动机的板子题。。我们直接构造字符串的$PAM$,然后在$fail$树上$dfs$,找到一个长度既是$4$的倍数,祖先中又有长度等于它的一半的字符串就行了。

 

 1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath>10 #include <queue>11 #include <stack>12 #include <map>13 #include <set>14 #define inf (1<<30)15 #define N (500010)16 #define il inline17 #define RG register18 #define ll long long19 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)20 21 using namespace std;22 23 struct edge{ int nt,to; }g[2*N];24 25 int ch[N][26],fa[N],l[N],head[N],cnt[N],n,la,sz,num,ans;26 char s[N];27 28 il int gi(){29     RG int x=0,q=1; RG char ch=getchar();30     while ((ch<0 || ch>9) && ch!=-) ch=getchar();31     if (ch==-) q=-1,ch=getchar();32     while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar();33     return q*x;34 }35 36 il void insert(RG int from,RG int to){37     g[++num]=(edge){head[from],to},head[from]=num; return;38 }39 40 il void add(RG int c,RG int n){41     RG int x=la; while (s[n-l[x]-1]!=s[n]) x=fa[x];42     if (!ch[x][c]){43     RG int v=++sz,k=fa[x]; l[v]=l[x]+2;44     while (s[n-l[k]-1]!=s[n]) k=fa[k];45     fa[v]=ch[k][c],ch[x][c]=v,insert(fa[v],v);46     }47     la=ch[x][c]; return;48 }49 50 il void dfs(RG int x){51     if (l[x]%4==0 && cnt[l[x]/2]) ans=max(ans,l[x]); ++cnt[l[x]];52     for (RG int i=head[x];i;i=g[i].nt) dfs(g[i].to); --cnt[l[x]]; return;53 }54 55 il void work(){56     n=gi(),scanf("%s",s+1),l[++sz]=-1,fa[0]=1;57     for (RG int i=1;i<=n;++i) add(s[i]-97,i);58     dfs(0),printf("%d\n",ans); return;59 }60 61 int main(){62     File("PAM");63     work();64     return 0;65 }

 

bzoj2342 [Shoi2011]双倍回文