P4287 [SHOI2011]双倍回文 回文自动机
P4287 [SHOI2011]双倍回文
题意
给定一个字符串\(S\),求它的最长双倍回文子串长度,双倍回文串是一个回文串且它的前一半和后一半都是相同的偶回文串。
\(|S|\le 5\cdot 10^5\)
分析
建回文自动机的过程中求出一个\(trans\)指针,\(trans\)指针的含义是小于等于当前节点长度一半的最长回文后缀,求出这个后直接冲就完事了。
Code
#include<bits/stdc++.h>
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=19930726;
const int maxn=2e6+10;
typedef pair<ll,ll> pii;
char s[maxn];
int n,now;
ll k;
ll ksm(ll a,ll b){
ll ret=1;
while(b){
if(b&1) ret=ret*a%mod;
b>>=1;
a=a*a%mod;
}
return ret;
}
struct PAM{
int son[maxn][26],fail[maxn],trans[maxn],len[maxn],tot,last;
pii a[maxn];
ll sz[maxn];
int cnt;
int newnode(int x){
++tot;
for(int i=0;i<26;i++) son[tot][i]=0;
fail[tot]=0;len[tot]=x;
return tot;
}
void init(){
tot=-1;newnode(0);newnode(-1);
fail[0]=1;
last=0;
}
int gao(int x){
while(s[now-len[x]-1]!=s[now]) x=fail[x];
return x;
}
void insert(){
int p=gao(last);
if(!son[p][s[now]-'a']){
int tmp=son[gao(fail[p])][s[now]-'a'];
son[p][s[now]-'a']=newnode(len[p]+2);
fail[tot]=tmp;
if(len[tot]<=2) trans[tot]=fail[tot];
else{
tmp=trans[p];
while(s[now-len[tmp]-1]!=s[now]||(len[tmp]+2)*2>len[tot]) tmp=fail[tmp];
trans[tot]=son[tmp][s[now]-'a'];
}
}
last=son[p][s[now]-'a'];
sz[last]++;
}
int gao(){
int ans=0;
for(int i=1;i<=tot;i++){
int x=trans[i];
if(len[i]%2==0&&len[x]%2==0&&len[x]*2==len[i]) ans=max(ans,len[i]);
}
return ans;
}
}P;
int main(){
//ios::sync_with_stdio(false);
//freopen("in","r",stdin);
scanf("%d",&n);
scanf("%s",s+1);
s[0]='$';
P.init();
for(now=1;now<=n;now++){
P.insert();
}
printf("%d\n",P.gao());
return 0;
}