Manacher 与回文串

用"镜子里抄答案"的思想,把最长回文子串从 O(n²) 做到 O(n)

一、要解决的问题

回文串指正读反读都一样的字符串,如 level、noon。经典问题:给定字符串 s(长度可达 107),求最长回文子串的长度,或统计回文子串总数。

朴素做法是中心扩展:枚举每个中心,向两边扩。但回文有奇偶两种中心(aba 中心是 b,abba 中心在两个 b 之间),要分两种情况写两遍,复杂度 O(n²) 也会超时。

Manacher 的两个天才想法:① 在字符之间插入特殊符号 #,把奇偶两种情况统一成一种;② 利用回文的对称性,右半边的答案可以从左半边"照抄",已算过的不再重算。

二、第一步:插入 # 统一奇偶

生活类比:回文就像照镜子——中心是镜面,左右两边互为镜像。偶数长度回文(如 abba)的"镜面"落在两个字符之间,奇数长度(如 aba)落在某个字符上,两种镜面处理起来很别扭。插入 # 的妙处:给每两个字符之间都造一个可以站镜面的位置,从此所有镜面都落在字符(或 #)上,统一处理。

把 s = "abba" 变成 t = "^#a#b#b#a#$"(首尾再加两个不同的哨兵防越界)。

约定:p[i] = 以 i 为中心的回文"臂长"(中心向单侧延伸的字符数,不含中心)
新串中以 i 为中心、臂长 p[i] 的回文 ↔ 原串中一个长度恰为 p[i] 的回文

例如 abba → #a#b#b#a#,正中间的 # 处 p = 4,对应原回文 "abba" 长 4;aba → #a#b#a#,中心 b 处 p = 3,对应 "aba" 长 3。从此只需处理一种中心,且原串回文长度直接等于 p[i],无需换算。

t = # a # b # b # a #(以 "abba" 为例,正中 # 处臂长 p = 4) # a # b #镜 b # a # 臂长 p = 4:镜面两侧各 4 格(左右互为镜像:a↔a、#↔#、b↔b、#↔#) 镜像区里原串字符正好 4 个(a b b a)→ 原回文长度 = p = 4
插入 # 后的镜像结构:臂长直接读出原串回文长度

三、第二步:镜像复用(核心)

维护两个量:c = 当前右边界最靠右的回文中心,R = 它对应的右边界。处理位置 i(i < R)时,i 关于 c 的镜像点是 i' = 2c − i。由于 [c−(R−c), R] 整段是回文,i 和 i' 的处境"对称",所以:

p[i] 的初始值 = min( p[i'], R − i ),然后再尝试继续向外扩展
以 c 为中心的大回文 [L, R] c(中心) i' = 2c − i i(待求) 对称:i 的回文可以从 i' 抄过来 R L 若 p[i'] 完全落在 [L, R] 内部 → p[i] = p[i'],直接抄,零成本 若 p[i'] 顶到左边界 L → p[i] 至少为 R − i,超出 R 的部分再逐个比较
镜像原理:回文的对称性让右半边的计算可以"照抄"左半边

为什么总复杂度是 O(n)?

"逐个比较向外扩展"这步看似暴力,但每次扩展成功都会让右边界 R 至少右移一格,而 R 单调不减、最多移动 n 次。所有扩展操作加起来是 O(n),抄答案的部分是 O(1),故总复杂度 O(n)。

四、模板代码

// t: 已处理成 ^#a#b#...#$ 形式,长度 m;p[i] 初值为 0
int c = 0, R = 0;
for (int i = 1; i < m - 1; i++) {
    p[i] = (i < R) ? min(p[2 * c - i], R - i) : 0;   // 镜像抄答案
    while (t[i + p[i] + 1] == t[i - p[i] - 1]) p[i]++;   // 继续扩展
    if (i + p[i] > R) { c = i; R = i + p[i]; }           // 更新最右回文
}
// 最长回文子串长度 = max(p[i])
// 回文子串总数 = Σ (p[i] + 1) / 2

五、走查一遍:s = "abba"

it[i]扩展后 p[i]对应原串回文(长度 = p[i])
2a1"a",长 1
3#0无(两侧 a、b 不等)
4b1"b",长 1
5#(正中)4"abba",长 4 ✓

建议自己拿 "abcbad" 完整走一遍 p 数组,是考场上默写模板前最好的热身。

六、能干什么 & 易错点

易错:① 镜像初值是 min(p[2c−i], R−i),漏掉 R−i 会越界抄错;② 新串首尾哨兵 ^、$ 必须互不相同且不在原串出现;③ 下标用 1-based 写 while 扩展最不容易错。

七、练习

考情提示:Manacher 在 NOI 大纲 2025 修订版中由 NOI 级下放到提高级 7 级,是 2026 年最典型的押题点,模板务必默写级熟练。

配套小测(5 题,即时判分)