Manacher 算法:线性回文提取
Time Radius Symmetry Space
Manacher 算法(马拉车算法)是解决最长回文子串问题的最优线性算法。它通过预处理消除字符串长度的奇偶差异,并利用已知的对称性信息跳过冗余计算。
1. 预处理:消除奇偶差异
回文串分为奇回文(如 aba,中心为字符)和偶回文(如 abba,中心为间隙)。
统一变换:在每个字符两侧及字符串首尾插入特殊字符(如 #),并在首尾添加不同的边界符(如 $ 和 @)以防止越界。
aba$#a#b#a#@abba$#a#b#b#a#@
性质:变换后的字符串长度始终为 。所有回文串在变换后的串中均表现为奇回文,其回文半径 与原串长度 的关系为 。
2. 核心原理:半径对称性 (Radius Symmetry)
2.1 状态定义
- :以预处理串位置 为中心的最长回文半径(包含 自身)。
- :当前探测到的最右边界回文串的中心 (Mirror Center)。
- :该回文串的最右端点 (Right Boundary),即 。
2.2 转移逻辑证明
对于当前位置 ,其相对于 的对称点为 。
定理: 的初始值可由下式确定:
证明:
- Case 1: 。由于 以 为对称中心,且 的回文范围完全包含在 的回文范围内,根据对称性, 的回文半径必然等于 的回文半径,即 。
- Case 2: 。此时 对称过去的部分超出了 的已知回文范围 。我们只能保证 在 以内的部分是对称的,即 。超出 的部分需要继续通过中心扩展来确定。
2.3 复杂度证明:势能分析
定理:Manacher 算法的时间复杂度为 。 每次成功的匹配都会导致 至少增加 1。由于 是单调不减的且最大为 ,故总复杂度为 。
3. 算法实现
🎯 综合练习
练习 1:[Luogu P4555] 最长双回文子串
题目:输入字符串 ,求 的最长双回文子串 的长度,使得 可以写成两个回文串拼接的形式。
Check Solution
解法:分别维护每个位置结尾的最长回文 和开始的最长回文 。
- 通过 Manacher 算法计算出每个位置的半径 。
- 更新边界:,。
- 递推补全:,。
- 遍历所有分割点,答案为 。
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int main() {
string s; cin >> s;
string t = "$#";
for (char c : s) { t += c; t += '#'; }
t += '@';
int n = t.size();
vector<int> d(n), L(n, 0), R(n, 0);
int m = 0, r = 0;
for (int i = 1; i < n - 1; i++) {
if (i < r) d[i] = min(d[2 * m - i], r - i);
else d[i] = 1;
while (t[i - d[i]] == t[i + d[i]]) d[i]++;
if (i + d[i] > r) { m = i; r = i + d[i]; }
L[i + d[i] - 1] = max(L[i + d[i] - 1], d[i] - 1);
R[i - d[i] + 1] = max(R[i - d[i] + 1], d[i] - 1);
}
for (int i = n - 2; i >= 1; i -= 2) L[i] = max(L[i], L[i + 2] - 2);
for (int i = 1; i <= n - 2; i += 2) R[i] = max(R[i], R[i - 2] - 2);
int ans = 0;
for (int i = 1; i <= n - 2; i += 2) {
if (L[i] && R[i + 2]) ans = max(ans, L[i] + R[i + 2]);
}
cout << ans << endl;
return 0;
}
练习 2:[Codeforces 7D] Palindrome Degree
题目:定义回文等级:若前缀是回文且其左半部分也是回文,则等级递增。求所有前缀等级之和。
Check Analysis
Manacher + DP:
- 利用 Manacher 判断每个前缀是否为回文(即 在变换后的串中)。
- 设 为前缀 的回文等级。
- 若 是回文,则 ;否则 。