[模板]manacher算法

来源:互联网 发布:固定循环编程注意? 编辑:程序博客网 时间:2024/06/01 20:54
给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.字符串长度len <= 11000000

题目来源:Luogu P3805

我们就假设长度为n吧,字符串为S,最长回文串为ans
先说一下几个显然的算法:

O(n3)暴力

直接枚举所有i[1,n)j(i,n],判断回文
判断方法就是枚举k[0,ji2]
若存在k,使Si+kSjk,则S非回文串,否则S为回文串

O(n2)暴力

分两种情况讨论:

2ans

显然枚举所有i[1,n]
枚举j[1,min{i,ni})找到第一个Si+jSij
2j+1更新ans

2ans

枚举所有i[1,n)
枚举j[0,min{i,ni1})找到第一个SijSi+j+1
2j+2更新ans

前方高能!!!

manacher

复杂度O(n)
网上是这样说的,可是我感觉不止啊
假设有一个字符串长这样:
abacab
我们先给它做个处理:
$#a#b#a#c#a#b#
设处理后的串为C,最长回文串为c
这样有两个好处:

不用管偶数长度的回文

不用管边界

也有些性质:

c=2ans+1

我们需要记录两个东西:max,p分别为当前搜到的最靠右的位置,和搜到那个位置的回文串中心。
f(i)表示以i为中心的最长回文串
因为是顺次搜,所以必定会有p<i
根据max,p的定义,有p<max
我们假设有以下数量关系:

i<max

因为C的区间[2pmax,max]是关于p对称的
所以f(i)f(2pi)我们可以在if(2p1)的基础上向两边扩张

imax

没搜到的有木有,所以像O(n2)暴力一样扩张
然后要搞大事啦:
p=i,max=i+f(i)没错,更新不可少
附代码:

#define N 11000010int len,g[2*N],f[2*N],m,p,ans;int main(){    char c=gc;    while(c<'a'&&c>'z')        c=gc;    g[0]=27;    while(c>='a'&&c<='z')    {        len+=2;        g[len]=c-'a'+1;        c=gc;    }    len++;    fr(i,1,len)    {        if(i<m)            f[i]=min(m-i,f[p+p-i]);        else            f[i]=1;        while(g[i+f[i]]==g[i-f[i]])            f[i]++;        if(i+f[i]>m)        {            m=i+f[i];            p=i;        }    }    fr(i,1,len)        ans=max(ans,f[i]);    printf("%d\n",ans-1);    rt 0;}
原创粉丝点击