https://subetter.com/algorithm/manacher-algorithm.html
p[i]=min(p[j],mx-i)
即p[i]为后面两者间的较小值,如果强行给它较大值,都将引发另一个值的变大。例如当
p[j]大于mx-i时。如果p[i]=p[j],将使得p[mx]变大(而事实上p[j],p[mx]都是固定值)
这对于第一种情况:
J有一部分是越过id回文串的左边界的,则i的回文串是不能超过id的右边界。如果越过即p[i]=p[j]则
d=c..以i为回文
b=c..以id为回文
b=a..以j为回文
于是乎a=d..说明id的回文还能放大,这是不允许的
对于第二种情况
当p[j]<mx-i时,如果强行将i=mx-i的话,则会出现
d=c...关于i对称
c=b...关于id对称
a=d...关于id对称
于是a=b,因而p[j]变大
(图中关于a,d的红线不应该划得超过黑线,应与之相等)
#include<bits/stdc++.h> #define N 2050001 using namespace std; int len,p[N],Case,ans; char ch[N],s[N*2]; void manacher() { int cnt=1;s[0]='%';s[1]='#'; for(int i=0;i<len;i++) { s[++cnt]=ch[i]; s[++cnt]='#'; } //在原串的基础上,在字符最开始加一个上"$",然后让每个字符的前后都是"#" //例如abc----->$#a#b#c#,于是len2的值为2*len1+2 int maxRight=0,id=0; for(int i=1;i<=cnt;i++) { if(i<maxRight) p[i]=min(p[2*id-i],maxRight-i); //p[2*id-i]是i关于id对称的另一个点,这个点的P值已算出来过 //maxright-i为i到maxright的距离 //取其两者较小值 else p[i]=1; while (i+p[i]<=cnt&&s[i-p[i]]==s[i+p[i]]) p[i]++; if(i+p[i]>maxRight) id=i,maxRight=i+p[i]; } for(int i=1;i<=cnt;i++) ans=max(ans,p[i]); ans--; } int main(){ while(1){ scanf("%s",ch);len=strlen(ch); if(len==3&&ch[0]=='E'&&ch[1]=='N'&&ch[2]=='D')break; memset(p,0,sizeof(p)); ans=1;manacher(); printf("Case %d: %d ",++Case,ans); } return 0; }