P3805 【模板】manacher算法
题目描述
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
字符串长度为n
输入输出格式
输入格式:
一行小写英文字符a,b,c...y,z组成的字符串S
输出格式:
一个整数表示答案
输入输出样例
说明
字符串长度len <= 11000000
记录p[i]表示i能向两边推(包括i)的最大距离,如果能求出p,则答案就是max(p)-1了(以i为中点的最长回文为2*p[i]-1,但这是加过字符后的答案,把加进去的字符干掉,最长回文就是p[i]-1)。假设当前能达到的最右边为R,对应的中点为pos,j是i的对称点。
1.当i<R时
由于L~R是回文,所以p[i]=p[j](i的最长回文和j的最长回文相同)。
这种情况是另一种:j的最长回文跳出L了。那么i的最长回文就不一定是j的最长回文了,但蓝色的肯定还是满足的。
综上所述,p[i]=min(p[2*pos-i],R-i)。
2.当i>=R时
由于后面是未知的,于是只能暴力处理了。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=22000010; int L; char a[N>>1],s[N]; int mid,maxr; int len[N]; void init() { scanf("%s",a); int l=strlen(a); for(int i=0;i<l;++i) s[++L]='#', s[++L]=a[i]; s[0]='@'; s[++L]='#'; } void manacher() { for(int i=1;i<=L;++i) { if(maxr>i) //i在右端点左边 len[i]=min(len[mid*2-i],maxr-i); //取与对称点回文长度和i->maxr的最小值 else //i在maxr右边 len[i]=1; for(;s[i+len[i]]==s[i-len[i]];++len[i]); if(i+len[i]>maxr) { maxr=i+len[i]; mid=i; } } } int main() { init(); manacher(); int ans=*max_element(len+1,len+L+1); printf("%d",ans-1); //多算了一次i,要减去1 return 0; }