在建立PAM求len的同时,我们要求出trans。
trans 指针的含义是小于等于当前节点长度的一半最长回文后缀。
当我们新建一个节点后,如果它的长度小于等于 2,那么这个节点的 trans 指针指向它的 fail 节点
否则的话,我们同理从它父亲的 trans 指针指向的节点开始跳 fail 指针
直到跳到某一个节点所表示的回文串的两侧都能扩展这个字符
并且拓展后的长度小于等于当前节点长度的一半
那么新建节点的 trans 的指针就指向该节点的儿子
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5e5+10;
struct PAM{
int nex[N][26],fail[N],len[N],tot,last,trans[N];
inline void init(){len[0]=0,len[1]=-1,fail[0]=fail[1]=1,tot=1,last=0;}
inline int insert(int x,int en,char *s){
int rt=last;
while(s[en]!=s[en-len[rt]-1]) rt=fail[rt];
if(!nex[rt][x]){
int tmp=fail[rt]; ++tot;
while(s[en]!=s[en-len[tmp]-1]) tmp=fail[tmp];
fail[tot]=nex[tmp][x];
nex[rt][x]=tot;
len[tot]=len[rt]+2;
if(len[tot]<=2) trans[tot]=fail[tot];
else{
int t=trans[rt];
while(s[en-len[t]-1]!=s[en]||((len[t]+2)<<1)>len[tot]) t=fail[t];
trans[tot]=nex[t][x];
}
}
last = nex[rt][x];
return len[last];
}
}p;
char a[N]; int n,res;
signed main(){
scanf("%d %s",&n,a+1); p.init();
for(int i=1;i<=n;i++) p.insert(a[i]-'a',i,a);
for(int i=2;i<=p.tot;i++)
if((p.len[p.trans[i]]<<1)==p.len[i]&&p.len[p.trans[i]]%2==0)
res=max(res,p.len[i]);
cout<<res;
return 0;
}