bzoj 2342: [Shoi2011]双倍回文

Description

Input

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

Output

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

Sample Input

16
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);
}

 

posted @ 2017-05-28 21:42  qt666  阅读(135)  评论(0编辑  收藏  举报