[LuoguP4287][SHOI2011]双倍回文(回文自动机)
作者:互联网
[LuoguP4287][SHOI2011]双倍回文(回文自动机)
题面
定义一个字符串为"双倍回文",当且仅当它是回文串,长度为4的倍数,且前一半和后一半的字符串都是回文串。如\(\texttt{abbaabba}\)
给出一个字符串\(S\),求它的最长双倍回文子串的长度。
\(|S|\leq 5 \times 10^5\)
分析
对于PAM上的每个节点,我们维护\(trans\),代表小于等于当前节点串长度一半的最长回文后缀,指向对应后缀的节点.求法和fail基本一样。
int y=t[p].trans;
while(s[pos-len(y)-1]!=s[pos]||(len(y)+2)*2>len(cur)) y=fail(y);
t[cur].trans=t[y].ch[c];
//和getfail类似,注意转移过来加了c之后长度为len(y)+2
然后对于每个节点,判断\(2len(trans(i))\)是否等于当前长度\(len(i)\),且\(4|len(i)\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 500000
#define maxc 26
using namespace std;
char s[maxn+5];
struct PAM{
#define fail(x) (t[x].fail)
#define len(x) (t[x].len)
struct node{
int ch[maxc];
int fail;
int len;
int trans;
}t[maxn+5];
int ptr,last;
void ini(){
ptr=1;
t[0].fail=1;
t[1].fail=0;
len(0)=0;
len(1)=-1;
last=0;
}
inline int get_fail(int x,int n){
while(s[n-len(x)-1]!=s[n]) x=fail(x);
return x;
}
void insert(int c,int pos){
int p=get_fail(last,pos);
if(t[p].ch[c]==0){
int cur=++ptr;
len(cur)=len(p)+2;
fail(cur)=t[get_fail(fail(p),pos)].ch[c];
t[p].ch[c]=cur;
if(len(cur)<=2) t[cur].trans=fail(cur);
else{
int y=t[p].trans;
while(s[pos-len(y)-1]!=s[pos]||(len(y)+2)*2>len(cur)) y=fail(y);
t[cur].trans=t[y].ch[c];
//和getfail类似,注意转移过来加了c之后长度为len(y)+2
}
}
last=t[p].ch[c];
}
int calc(){
int ans=0;
for(int i=2;i<=ptr;i++){
if(len(t[i].trans)*2==len(i)&&len(i)%4==0) ans=max(ans,len(i));
}
return ans;
}
}T;
int n;
int main(){
scanf("%d",&n);
scanf("%s",s+1);
T.ini();
for(int i=1;i<=n;i++) T.insert(s[i]-'a',i);
printf("%d\n",T.calc());
}
标签:ch,cur,int,len,LuoguP4287,fail,SHOI2011,回文 来源: https://www.cnblogs.com/birchtree/p/12391940.html