专栏文章

Manacher,不知道怎么进入提高级大纲的老登

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mingx7xf
此快照首次捕获于
2025/12/02 02:13
3 个月前
此快照最后确认于
2025/12/02 02:13
3 个月前
查看原文
下文的所有字符串,下标默认从 11 开始。
在字符串的开头结尾,以及两字符之间,插入一个符号 #,比如 manacher 字符串就变为 #m#a#n#a#c#h#e#r#。这样做是为了让两种回文子串的情况(长度为奇、偶)归并为一种,减少分类讨论。
Manacher 算法,可以在线性复杂度内,处理出 ff 数组,其中 fif_i 表示以下标 ii 的字符为中心,最大的回文子串长度。
假设已经处理了 f1,f2,,fi1f_1,f_2,\dots,f_{i-1} 的值,需要求 fif_i 的值,且已经知道了以位置 t[1,i1]t\in[1,i-1] 为中心,所有回文串的右端点的最大值为 RR,其对应的回文中心为 CC
对于求 fif_i,分两种情况:
  • i>Ri>R,这个时候已有条件无法处理,只能暴力扩展。
  • iRi\leq R,图示如下:
这个时候,对 iRi\leq R 的情况继续讨论:
  • ii' 的回文区域在 [L,R][L,R] 内,但左端没到 LL
显然,fi=fif_i=f_{i'}
  • ii 的回文区域的左端超过了 LL
这个时候会发现,第 11 段与第 33 段相同,第 33 段与第 44 段相同。如果 ii 可以扩展直至包含 2,42,4 段,则 2,42,4 段也相同,那么 1,21,2 段就相同。
但此时以 CC 为中心的回文串没有扩展到 1,21,2 段,故矛盾,也就是这种情况不存在。
  • ii 的回文区域的左端正好是 LL
这个时候不好判断,暴力扩展即可。
该算法流程完毕,感性理解可以得出复杂度为线性。
代码CPP
cin>>str,s="#";
for (auto i:str)
    s+=i,s+='#';
n=s.size(),s=' '+s;
fo(i,1,n){
    if (i>r) p[i]=1;
    else p[i]=min(r-i,p[2*t-i]);
    while (i+p[i]<=n&&i-p[i]>=1&&s[i+p[i]]==s[i-p[i]])
        p[i]++;
    if (p[i]+i>r)
        r=i+p[i],t=i;
    mx=max(mx,p[i]-1);
}
图片出处:link

评论

0 条评论,欢迎与作者交流。

正在加载评论...