给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度.
字符串长度len <= 11000000
题目来源:Luogu P3805
我们就假设长度为
n
吧,字符串为
先说一下几个显然的算法:
O(n3) 暴力
直接枚举所有
i∈[1,n)
j∈(i,n]
,判断回文
判断方法就是枚举
k∈[0,⌊j−i2⌋]
若存在
k
,使
O(n2) 暴力
分两种情况讨论:
2∤ans
显然枚举所有
i∈[1,n]
枚举
j∈[1,min{i,n−i})
找到第一个
Si+j≠Si−j
用
2j+1
更新
ans
2∣ans
枚举所有
i∈[1,n)
枚举
j∈[0,min{i,n−i−1})
找到第一个
Si−j≠Si+j+1
用
2j+2
更新
ans
前方高能!!!
manacher
复杂度
O(n)
网上是这样说的,可是我感觉不止啊
假设有一个字符串长这样:
abacab
我们先给它做个处理:
$#a#b#a#c#a#b#
设处理后的串为
C
,最长回文串为
这样有两个好处:
不用管偶数长度的回文
不用管边界
也有些性质:
c=2ans+1
我们需要记录两个东西:
max,p
分别为当前搜到的最靠右的位置,和搜到那个位置的回文串中心。
设
f(i)
表示以
i
为中心的最长回文串
因为是顺次搜,所以必定会有
根据
max,p
的定义,有
p<max
我们假设有以下数量关系:
i<max
因为
C
的区间
所以
i≥max
没搜到的有木有,所以像
O(n2)
暴力一样扩张
然后要搞大事啦:
p=i,max=i+f(i)
没错,更新不可少
附代码:
#define N 11000010
int 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;
}