Manacher 通过记录已匹配的最右位置和对应的对称中心 利用和对称性来跳过一些没用的比较
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int M =111000;
char s[M];
char t[2*M]; //转换后字符串长度为奇数
int p[2*M];// p[i] 以i为中心点的回文的右端长度
int len;
void Init()
{
int i;
len=strlen(s);
t[0]='@';//防止越界
for(int i=1;i<=2*len;i+=2)
{
t[i]='#';
t[i+1]=s[i/2];
}
t[2*len+1]='#';//最后一个
t[2*len+2]='$';//防止越界
t[2*len+3]=0;//结束标记
len=2*len+1;//转换后 字符串长度
}
void MANACHER()
{
int mx=0,ans=0,po=0;// i之前最大p为po po最右端点为mx
for(int i=1;i<=len;i++)
{
if(mx>i)
{
p[i]=min(p[2*po-i],mx-i); // i关于po对称点为 (i+j)/2=po j=2*po-i
//情况1 j-len[j]~~i+len[j]如果在po范围内-> lem[i]>=len[j] (画个图推一个咯)
//情况2 如果i+len[j]>mx 现在只能确定i-(mx-i)~~i+(mx-i)为回文 因为mx之后的没匹配过不能确定 (画个图推一个咯)
}
else
{
p[i]=1;//mx之后的位置还没有被匹配过 所以此时开始推
}
while(t[i-p[i]]==t[i+p[i]])
p[i]++;
if(p[i]+i>mx)//update
{
mx=p[i]+i;
po=i;
}
ans=max(ans,p[i]);
}
ans-=1;// 新串回文长度为 2*p[i]-1 '#'的个数比原串字符多1 (画图推) x+(x-1)==2*p[i]-1 x=p[i] 所以其它字符即原串的回文长度为p[i]-1
printf("%d\n",ans);
}
int main()
{
while(scanf("%s",s)!=EOF)
{
Init();
MANACHER();
}
return 0;
}