Input
输入分为两行,第一行为一个整数,表示字符串的长度,第二行有个连续的小写的英文字符,表示字符串的内容。
Output
输出文件只有一行,即:输入数据中字符串的最长双倍回文子串的长度,如果双倍回文子串不存在,则输出0。
Sample Input
16
ggabaabaabaaball
Sample Output
12
HINT
N<=500000
(详情看注释,因为没有理解Manacher算法数组的含义,这道题没做出来,太菜了。)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2e6+10;
int n,m,f[maxn],g[maxn];
char a[maxn],s[maxn];
int main(void)
{
while(cin>>n)
{
int i,r,p;
scanf("%s",a+1);
for(int i=1;i<=n;i++)
s[i<<1]=a[i],s[i<<1|1]='#';
s[0]='$',s[1]='#',s[m=(n+1)<<1]='@';
for(r=p=0,f[1]=1,i=2;i<m;i++)
{
for(f[i]=r>i?min(r-i,f[p*2-i]):1;s[i-f[i]]==s[i+f[i]];f[i]++);
if(i+f[i]>r) r=i+f[i],p=i;
}
int ans=0;
//串的中心显然是填充字符,所以i初始值为3,并且i+=2。
for(int i=3;i<m;i+=2)
{
int len=f[i]-1;
while(len>3)
{
if(len%4==0)
{
//如果比当前答案小直接跳出循环,节省时间
if(len<ans) break;
//找到串的左端
int l=i-len;
int r=i;
//找到左边串的中心
int m=(l+r)/2;
//如果左边的串能覆盖到i,保证左边的串也为回文串。
if(m+f[m]-1>=i)
ans=max(ans,len);
}
len-=2;
}
}
printf("%d
",ans);
}
return 0;
}
/*
8
aaaaaaaa
12
abbaabbaabba
12
abaabaabaaba
*/