[模板] manacher
[模板] manacher
manacher 算法,又叫马拉车算法,是一种在线性复杂度内求得任意长度为奇数的字符串的最长回文子串的算法。
算法构造思路
-
核心是维护当前最长回文覆盖和最远右端点。
-
可以维护两个指针:\(pos\) 和 \(maxr\),其中 \(maxr\) 表示当前回文子串中的最右端,\(pos\) 为取到最右端的回文子串的回文中心。
画个图理解一下:
其中 \(r'\) 是以 \(pos\) 为回文中心的回文子串的最左端。注意:是闭区间。
考虑当前点 \(i\) 的最长回文半径如何求得,先找到 \(i\) 关于 \(pos\) 的对称点 \(i'\)。
分两种情况来讨论:
- \(i'\) 的最长回文子串覆盖区间 \(\subseteq\) \([r',maxr]\) ,那么直接继承过来即可,因为没有办法再向两边扩展了。
- \(i'\) 的最长回文子串覆盖区间 \(\not\subseteq\) \([r',maxr]\) ,继承过来边界值再向两边暴力扩展,直到不能扩展为止,并更新 \(maxr\) 和 \(pos\) 的值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 11000000 + 10;
char s[maxn<<1];
int r[maxn<<1],maxr,cnt=0,ans;
void init(){
char ch=getchar();
s[0]='@';s[cnt=1]='|';
while(ch>'z' || ch<'a')ch=getchar();
while(ch>='a' && ch<='z')s[++cnt]=ch,s[++cnt]='|',ch=getchar();
}
int main(){
init();maxr=0;
int mid=0;
for(int i=1;i<=cnt;i++){
if(i<=maxr)r[i]=min(r[mid*2-i],maxr-i+1);
while(s[i-r[i]]==s[i+r[i]])r[i]++;
if(i+r[i]-1>maxr){maxr=i+r[i]-1;mid=i;}
ans=max(ans,r[i]-1);
}
printf("%d\n",ans);
return 0;
}