学习NOTE 5——Manacher(马拉车)
前情提要
这其实是我在没学马拉车,只看题解的前提下写出来的依托答辩。
正题
下面进入正题。咳咳
是什么
马拉车?不就是马拉着车吗? 其实就是Manacher的音译。
Manacher算法是字符串的算法之一,是用于计算一个字符串里的最长回文串长度的算法。
example: aaa的最长回文串长度为 \(3\),abcbac的长度为 \(5\)。
怎么实现
想要计算,就得先从例子入手来分析:
例:
ababa:最长回文串长度为\(5\),中心为第三个a,下标为 \(3\)(以下所有字符串下标均从\(1\)开始,包括代码);abccba:最长回文串长度为\(6\),中心为两个c中间,下标为 ?
不对!
为什么偶数长度的回文字符串的回文中心在字符中间?而不像奇数长度的一样,在字符上。这不好表示回文中心啊。
所以我们可以把字符串变为奇数长度的!
至于怎么变呢?在每一个字符两边加#!
比如:
abccba变为#a#b#c#c#b#a#ababa变为#a#b#a#b#a#。
这样既让偶数长度的变成了奇数的,又不影响字符串的回文性。好方法!!
接下来我们令\(p_i\)记录:以当前第\(i\)为回文中心是最长回文“子”串长度。
考虑当前需要求出 \(p_i\)。我们可以记录一个 \(r\),用来表示在所有 \(1 \le j < i\) 的 \(j\) 中,以 \(j\) 为中心点的回文串的右端点中,最右的那一个。记这个 \(r\) 为右端点的回文串的中心点为 \(j'\)。此时我们需要进行分类讨论:
1. \(r>i\)
此时我们可以得到下图:

这个图是什么意思?我们首先可以找到 \(i\) 以 \(j'\) 为对称中心的对称点 \(i'=j'\times2-i\)。
注:\((i+i')/2=j'\rightarrow i'=j'\times2-i\)
然后,因为这一整个是一个回文串,所以,\(i'\) 下面那一段(指那一段子串)和 \(i\) 下面那一段一定也相同。所以在这种情况下,\(p_i=p_{i'}\),可以直接得出!
但是!情况不一定总是这么好。在 \(r>i\) 的情况中,还有另外一种情况:

如图,当 \(p_{i'}\) 很大的时候,这一段可能超出了整个大回文串,当这个子串对称到以 \(i\) 为中心的这边时,右端点超过了 \(r\),而我们并不清楚超出的部分。
在这种情况下,我们不能保证 \(i\) 的回文长度一定有这么长,只能保证从 \(i\) 到 \(r\) 这一段一定回文。所以,我们可以先 \(p_i\leftarrow r-i\),然后计算 \(p_i\) 的最终值。
这样,\(r>i\) 的情况暂时被我们解决了。
在每次更新完 \(p_i\) 后,注意要实时更新 \(r\) 和 \(j'\),用来计算后面的答案。
2.\(r<i\)
这是就不一样了,看图:

可以看出,没有任何可以使用的信息,所以只能计算 \(p_i\) 了。此时也需要更新 \(r\)。
遍历 \(1 \sim n\) 重复如上过程,即可得到所有 \(p_i\)。因为在计算之前在字符串中还插入了一些 #,所以最终答案其实就是: $$\max_{1 \sim n} (p_i-1)$$。
代码
PID:P3805
终于到代码啦~
其实代码很短~ (不要剧透)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=22*1e6+10;
int p[N],ans,j,r;
//p[i]表示以i为中心的回文半径(包括中心点本身)
string s;
char c;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
while(cin>>c) s+=c,s+="#";//将偶数长度变为奇数长度
s=" #"+s;//开头还没加
for(int i=1;i<=s.size();i++){
// 核心:若i在当前最右回文边界r内,则利用对称性初始化p[i]
// 否则p[i]从1开始(单个字符一定是回文)
p[i]=r>i?min(r-i,p[j*2-i]):1;
// ↑ ↑
// 不能超出边界 对称点的回文半径
while(s[i-p[i]]==s[i+p[i]]) p[i]++;//尝试扩大回文半径
//如果当前回文右边界超过了之前的,更新中心和右边界
if(p[i]+i>r){
j=i;
r=i+p[i];
}
}
for(int i=1;i<=s.size();i++) ans=max(ans,p[i]-1);//求最大值
//因为之前加了#,故要-1
cout<<ans;
return 0 ;
}
注: 部分内容参考:Eason_cyx的题解,感谢dalao!!

浙公网安备 33010602011771号