bzoj 2342: [Shoi2011]双倍回文
Description
Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
ggabaabaabaaball
Sample Output
12
HINT
N<=500000
Source
第二道回文自动机的题了...
这道题就是找沿着fail找到能找到一个点使len[u]==2*len[u]&&len[u]%4==0;
按fail连边之后,在fail树上dfs即可(可以对len开一个桶)
#include<cstdio> #include<algorithm> #include<cmath> #include<iostream> #include<cstring> using namespace std; typedef long long ll; const int N=600050; int gi() { int x=0,flag=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();} while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar(); return x*flag; } int len[N],nxt[N][30],fail[N],cnt[N],last,tt; int head[N],nxt2[N],to[N],cnt2,l,num[N],ans; char s[N]; void insert(int c,int n){ int cur=last; while(s[n-len[cur]-1]!=s[n]) cur=fail[cur]; if(!nxt[cur][c]){ int now=++tt,la=fail[cur];len[now]=len[cur]+2; while(s[n-len[la]-1]!=s[n]) la=fail[la]; fail[now]=nxt[la][c],nxt[cur][c]=now; } last=nxt[cur][c];cnt[last]++; } void lnk(int x,int y){ to[++cnt2]=y,nxt2[cnt2]=head[x],head[x]=cnt2; } void dfs(int x){ if(len[x]%4==0&&num[len[x]/2]) ans=max(ans,len[x]); num[len[x]]--; for(int i=head[x];i;i=nxt2[i]) dfs(to[i]); num[len[x]]++; } int main(){ l=gi();len[++tt]=-1;fail[0]=1; scanf("%s",s+1); for(int i=1;i<=l;i++) insert(s[i]-'a',i); for(int i=1;i<=tt;i++) lnk(fail[i],i); dfs(0);printf("%d\n",ans); }