https://www.lydsy.com/JudgeOnline/problem.php?id=2342
解法一:
对原串构建回文自动机
抽离fail树,从根开始dfs
设len[x]表示节点x表示的最长回文子串长度
在fail树上,x到根节点的路径上的点表示的字符串包含了x代表的回文子串的所有回文后缀/前缀
所以若dfs到了x,若len[x]为偶数,标记len[x]*2,如果在x的子树中能找到len为len[x]*2的点,那么len[x]*2*2就可以用来更新答案
#include<cstdio> #include<algorithm> using namespace std; #define N 500001 char ss[N+1]; int s[N+1]; int tot=1,last; int len[N],fail[N],tr[N][26]; int p,c,np,t; bool ok[N<<1]; int ans; int front[N],to[N],nxt[N],cnt; void add(int u,int v) { to[++cnt]=v; nxt[cnt]=front[u]; front[u]=cnt; } void extend(int i) { p=last; c=s[i]; while(s[i-1-len[p]]!=c) p=fail[p]; if(!tr[p][c]) { np=++tot; len[np]=len[p]+2; t=fail[p]; while(s[i-1-len[t]]!=c) t=fail[t]; fail[np]=tr[t][c]; add(fail[np],np); tr[p][c]=np; } else np=tr[p][c]; last=np; } void dfs(int x) { if(ok[len[x]]) ans=max(ans,len[x]); if(!(len[x]&1)) ok[len[x]<<1]=true; for(int i=front[x];i;i=nxt[i]) dfs(to[i]); if(!(len[x]&1)) ok[len[x]<<1]=false; } int main() { int n; scanf("%d",&n); scanf("%s",ss+1); s[0]=-1; for(int i=1;i<=n;++i) s[i]=ss[i]-'a'; fail[0]=1; len[1]=-1; for(int i=1;i<=n;++i) extend(i); dfs(0); printf("%d",ans); }