题目大意
在长度为n的字符串中找一个最长的连续子串,使其为回文串。
n<=5*10^5。
M开头的算法
manacher裸题。
我们在字符之间以及头尾加入’$’,并在最前和最后加入’&’(这是用来防止越界的)。
设f[i]为新字符串中第i个字符为中心,i-f[i]..i+f[i]这个部分是一个回文串,且f[i]最大。
我们设一个j,使当前j+f[j]最大。
当一个i<=j+f[j]时,我们容易通过对称性得到f[i]=f[j*2-i]。
但我们要防止这样做超过了j+f[j]导致失去对称性,所以f[i]=min(f[j*2-i],j+f[j]-i)。
然后更新j。
参考代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=5000000+100;
int f[maxn*2];
char s[maxn*2],ch;
int i,j,k,l,t,n,m,ans;
int main(){
n=3;
while ((ch=getchar())>='a'&&ch<='z') s[n=n+2]=ch;
s[1]='&';
s[n+2]='&';
n+=2;
fo(i,2,n-1)
if (i%2==0) s[i]='$';
fo(i,2,n-1){
if (i>j+f[j]){
f[i]=0;
while (s[i-f[i]-1]==s[i+f[i]+1]) f[i]++;
j=i;
}
else{
f[i]=min(f[2*j-i],j+f[j]-i);
while (s[i-f[i]-1]==s[i+f[i]+1]) f[i]++;
if (i+f[i]>j+f[j]) j=i;
}
ans=max(ans,f[i]);
}
printf("%d\n",ans);
return 0;
}