求最长双倍回文子串。
考虑建PAM,我们可以知道最长回文子串,但是如何知道最长双倍回文子串呢?
我们发现如果这个子串是双倍回文子串,那么该子串<=len/2的最长回文子串一定是=len/2的,我们可以再记录一个fail'表示<=len/2的最长回文子串后缀。
求答案的时候枚举每个位置判断fail'的len即可。
对于fail'的求法,类似fail的求法再判断len的限制即可。
还有一种方法,就是建完PAM以后在遍历一遍回文树,并用个桶实时存储当前每个长度的个数。每次看看有没有即可。
或者可以用manacher来实现。
#include<cstdio>
#define N 500010
#define db double
#define ll long long
#define fo(x,a,b) for (int x=(a);x<=(b);x++)
#define fd(x,a,b) for (int x=(a);x>=(b);x--)
using namespace std;
int n,ans=0;
char s[N];
struct PAM {
int t[N<<1][26],len[N<<1],fail[N<<1],trans[N<<1],tot=1,las;
void init() {
len[0]=0,fail[0]=trans[0]=1;
len[1]=-1,fail[1]=0,tot=1,las=1;
}
int get_fail(int pos,int x) {
while (s[pos-len[x]-1]!=s[pos])
x=fail[x];
return x;
}
int get_fail(int pos,int x,int son,int lim) {
while (s[pos-len[x]-1]!=s[pos]||len[t[x][son]]>lim)
x=fail[x];
return x;
}
void ins(int x) {
int now=get_fail(x,las);
if (! t[now][s[x]-'a']) {
len[++tot]=len[now]+2;
int temp=get_fail(x,fail[now]);
fail[tot]=t[temp][s[x]-'a'];
if (len[tot]<=2) trans[tot]=fail[tot];
else {
temp=get_fail(x,trans[now],s[x]-'a',len[tot]/2);
trans[tot]=t[temp][s[x]-'a'];
}
t[now][s[x]-'a']=tot;
}
las=t[now][s[x]-'a'];
}
int query() {
int res=0;
fo(i,2,tot) {
if (len[i]%4==0&&len[trans[i]]*2==len[i]) {
if (len[i]>res) res=len[i];
}
}
return res;
}
}tr;
int main() {
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%d%s",&n,s+1);
tr.init();
fo(i,1,n) tr.ins(i);
ans=tr.query();
printf("%d
",ans);
return 0;
}