【模板】manacher 题解
算法介绍
Manacher,是一种用于求解字符串中最长回文串的算法。它可以在
算法流程
下记 ababa
的长度是
下面所说的“暴力计算”均指如下代码(假设当前在
while(s[i+p[i]] == s[i-p[i]]) p[i]++;
首先处理一个问题:有些回文串长度是偶数,有些是奇数。奇数可以枚举中心点;但是偶数不行!为了解决这个问题,我们可以在所有字符之间插入一个 #
,这样偶回文串就被我们转换成了奇回文串了。
考虑当前需要求出
-
r>i
此时我们可以得到下图:
这个图是什么意思?我们首先可以找到
但是!情况不一定总是这么好。在
如图,当
这样,
在每次更新完
-
r<i
此时的情况如图:
此时可以很清晰地看出,没有任何可以使用的信息,所以只能暴力计算
遍历 #
,所以最终答案其实就是
正确性证明
首先正确性是显然的。
对于复杂度,我们可以感性理解一下:在上面的三种情况中,第一种是
代码实现
#include <bits/stdc++.h>
using namespace std;
int p[30000005], mx, id;
//注意:本题数据范围较大,要注意数组大小
//代码中 mx 即为讲解中的 r,id 为讲解中的 j'
int main() {
string s = "##";
char c; while(cin >> c) s += c, s += "#";
//插入 #;为防止越界,在最前面也插一个 #
int n = s.size(); s = ' ' + s;
for(int i = 1;i <= n;i++) {
p[i] = mx > i ? min(p[id*2-i], mx-i) : 1; //三目运算符,分别对应三种情况
while(s[i + p[i]] == s[i - p[i]]) p[i]++; //暴力计算 p[i]
if(i + p[i] > mx) mx = i + p[i], id = i; //更新右端点 r
} int ans = 0; for(int i = 1;i <= n;i++) ans = max(ans, p[i]-1);
cout << ans << endl;
return 0;
}