manacher算法是什么?
这是一种求最长回文字串的算法。
首先要采用一种方法,向原串中每隔一个字符加入一个没有在原串中出现过的字符,这样能够避免分类讨论奇数长度的回文串和偶数长度的回文串。同时再在头部和尾部加入两个不相同的字符,防止寻找时溢出字符串范围
例如:abba这个串如果向中间加入$,头部加入!,尾部加入,经过了刚才的操作后变成了!$a$b$b$a$
考虑暴力求法:枚举每一个点,向左和右分别寻找,如果两个寻找到的字符相等,那么以这个点为中心的回文串长度加2,时间复杂度O(n2)
在下面这个表中,@代表匹配的中心,=代表向外扩充的位置。

字符 ! $ a $ b $ b $ a $
第一次匹配 @
第二次匹配 @
第三次匹配 = @ =
第四次匹配 @
第五次匹配 = @ =
第六次匹配 = = = = @ = = = =
第七次匹配 = @ =
第八次匹配 @
第九次匹配 = @ =
第十次匹配 @
第十一次匹配 @

可以看出,上面有些地方是被重复统计很多次的,可以利用回文串的对称性来进行优化。也就是说,如果一个串T含于一个已知的回文串S内,而且这个串关于回文串S的对称中心对称的串S是回文的,则这个串是回文的。
记录一个数组pi代表以i为中心的最大回文半径,那么显然可以给出下面这个伪代码:

int id,rmax,p[maxn+10],ans;
//id代表能使以该点为回文中心的回文串末尾位置最大的点
//rmax代表以id为回文中心的最长回文串的末尾坐标
//ans记录答案
init();
id=rmax=p[1]=1;
for(i=2->len)
{
    if(i in 1..rmax)
    {
        p[i]=min(p[i与id对称的点],i与rmax的距离);//因为范围不能超过回文串的长度
    }
    else
    {
        p[i]=1;
    }
    while(找到的串长度还可以延伸)
    {
        ++p[i];
    }
    if(可以更新id和rmax)
    {
        更新id和rmax;
    }
    ans=max(ans,p[i]-1);
}

那么按照这个算法匹配的结果是怎样的呢?
在下面这个表中,@代表匹配的中心,=代表向外扩充的位置,-代表由以前的串而可以知道有回文的位置。

字符 ! $ a $ b $ b $ a $
第一次匹配 @
第二次匹配 @
第三次匹配 = @ =
第四次匹配 @
第五次匹配 = @ =
第六次匹配 = = = = @ = = = =
第七次匹配 - @ -
第八次匹配 @
第九次匹配 - @ -
第十次匹配 @
第十一次匹配 @

可以看出,虽然降低的次数不是很多,但是确实降低了。
复杂度?
O(n),每个位置平均被扫描两次,如果只讨论以一个点向右扫描的位置,那么每个位置被扫描不到一次(可以多举几个例子来验证一下)。至于最终答案为什么是max(pi1),这个随便举几个例子就好了。
代码

#include <cstdio>
#include <cstring>
#include <iostream>

const int maxn=1000000;

char s[maxn+10],a[(maxn<<1)+10];
int len,p[(maxn<<1)+10],id,rmax,ans,c;

inline int solve()
{
  ++c;
  a[0]='!';
  a[1]='#';
  for(register int i=1; i<=len; ++i)
    {
      a[i<<1]=s[i];
      a[i<<1|1]='#';
    }
  len=len<<1|1;
  a[len+1]='&';
  memset(p,0,sizeof p);
  id=1;
  rmax=1;
  p[1]=1;
  for(register int i=2; i<=len; ++i)
    {
      if(i>rmax)
    {
      p[i]=1;
    }
      else
    {
      if(p[(id<<1)-i]<rmax-i)
        {
          p[i]=p[(id<<1)-i];
        }
      else
        {
          p[i]=rmax-i;
        }
    }
      while(a[i+p[i]]==a[i-p[i]])
    {
      ++p[i];
    }
      if(rmax<i+p[i]-1)
    {
      rmax=i+p[i]-1;
      id=i;
    }
    }
  ans=0;
  for(register int i=1; i<=len; i++)
    {
      if(p[i]-1>ans)
    {
      ans=p[i]-1;
    }
    }
  printf("Case %d: %d\n",c,ans);
  return 0;
}

int main()
{
  while(1)
    {
      scanf("%s",s+1);
      len=strlen(s+1);
      if((len==3)&&(s[1]=='E')&&(s[2]=='N')&&(s[3]='D'))
    {
      break;
    }
      solve();
    }
  return 0;
}