manacher算法主要是处理字符串中关于回文串的问题的,它可以在 O(n) 的时间处理出以字符串中每一个字符为中心的回文串半径,由于将原字符串处理成两倍长度的新串,在每两个字符之间加入一个特定的特殊字符,因此原本长度为偶数的回文串就成了以中间特殊字符为中心的奇数长度的回文串了。
模板是从 kuangbin 巨巨的模板改过来的。
有注释版:
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 using namespace std;
5
6 const int maxn=1e6+5;
7 char s[maxn],t[maxn<<1]; //s是原串,t是倍长后的串,p是以某个字符为中心的回文串长度,p[i]-1 就是以 i 字符为中心的回文串在原串中的长度
8 int p[maxn<<1];
9
10 void manacher(){
11 int len=strlen(s),l=0; //原串从0开始
12 t[l++]='$'; //开头字符是一个特殊字符
13 t[l++]='#'; //倍长串中间的间隔都用这个字符
14 for(int i=0;i<len;++i){ //倍长原串(原串s[i]对应新串t[2*i+2],奇数下标表示两字符中间位置,偶数字符表示原串字符)
15 t[l++]=s[i];
16 t[l++]='#';
17 }
18 t[l]=0; //设置新串结尾为0
19 int maxx=0,num=0; //maxx是已经判断过的最远长度,num是到达最远长度的那个回文串中心字符位置
20 for(int i=0;i<l;++i){
21 p[i]=maxx>i?min(p[2*num-i],maxx-i):1; //若当前字符小于已经判断过的最远长度,那么就定初始值是 i关于num对称的位置的回文串长度 和 当前位置到最远距离的长度 的最小值,若还没有判断到过,那么就初始为1
22 while(t[i+p[i]]==t[i-p[i]])p[i]++; //判断直到不构成回文串
23 if(i+p[i]>maxx){ //判断是否拓展到更远位置
24 maxx=i+p[i];
25 num=i;
26 }
27 }
28 }
木有注释版:
1 #include<stdio.h>
2 #include<string.h>
3 #include<algorithm>
4 using namespace std;
5
6 const int maxn=1e6+5;
7 char s[maxn],t[maxn<<1];
8 int p[maxn<<1];
9
10 void manacher(){
11 int len=strlen(s),l=0;
12 t[l++]='$';
13 t[l++]='#';
14 for(int i=0;i<len;++i){
15 t[l++]=s[i];
16 t[l++]='#';
17 }
18 t[l]=0;
19 int maxx=0,num=0;
20 for(int i=0;i<l;++i){
21 p[i]=maxx>i?min(p[2*num-i],maxx-i):1;
22 while(t[i+p[i]]==t[i-p[i]])p[i]++;
23 if(i+p[i]>maxx){
24 maxx=i+p[i];
25 num=i;
26 }
27 }
28 }