bzoj2342 [Shoi2011]双倍回文
Description
Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
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 inline 17 #define RG register 18 #define ll long long 19 #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 }