双倍回文
如果 s 能够写成 wwRwwR 的形式,则称 s 是双倍回文。
s 的长度是 4 的倍数,前后两半都是相同的回文。
对于给定的字符串,计算它的最长双倍回文串的长度。
N<=500000
yyb的题解
发现这个长度为自身一半的的回文串是可以方便地转移的。
对于每个节点,我们维护一个half来表示长度最长的、不超过它长度一半的那个祖先节点
这样子只需要判断一下当前点的half长度是否是一半,并且当前串的长度是四的倍数就好了
找 half 就用 p 的 half 来跳就行了。
#include
using namespace std;
template T read(){
T x=0,w=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*w;
}
template T read(T&x){
return x=read();
}
#define co const
#define il inline
typedef long long LL;
co int N=500000+10;
char s[N];
int last=1,tot=1;
int ch[N][26],fa[N]={1,1},len[N]={0,-1},half[N];
int get_fa(int x,int i){
while(s[i-len[x]-1]!=s[i]) x=fa[x];
return x;
}
void extend(int i){
int p=get_fa(last,i);
int x=ch[p][s[i]-'a'];
if(!x){
x=++tot;
fa[x]=ch[get_fa(fa[p],i)][s[i]-'a'];
len[x]=len[p]+2;
ch[p][s[i]-'a']=x;
if(len[x]==1) half[x]=0;
else{
int q=half[p];
while(s[i-len[q]-1]!=s[i]||(len[q]+2)<<1>len[x]) q=fa[q];
half[x]=ch[q][s[i]-'a'];
}
}
last=x;
}
int main(){
int n=read();
scanf("%s",s+1);
for(int i=1;i<=n;++i) extend(i);
int ans=0;
for(int i=1;i<=tot;++i)
if(len[half[i]]<<1==len[i]&&len[i]%4==0)
ans=max(ans,len[i]);
printf("%d\n",ans);
return 0;
}