【模板】最长回文串长度:manacher 算法

\(pa_i\) 表示以 \(i\) 为中心的(原串的)回文串长度

点击查看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
int n,m,pa[22000010];
char buf[11000010],a[22000010];
void manacher(char *a){
    int len=strlen(a+1);
    for(int i=1,mid=0,r=0;i<=len;i++){
        if(i<=r) pa[i]=min(pa[mid*2-i],r-i);
        while(a[i-pa[i]-1]==a[i+pa[i]+1]) pa[i]++;
        if(i+pa[i]>r) r=i+pa[mid=i]; 
    }
}
int main(){
//  #ifdef LOCAL
//      freopen("input.in","r",stdin);
//  #endif
    scanf("%s",buf+1),n=strlen(buf+1);
    a[0]='~',a[m=1]='|';
    for(int i=1;i<=n;i++) a[++m]=buf[i],a[++m]='|';
    a[++m]=0;
    printf("%d\n",manacher(a));
    return 0;
}

注意这个处理,是 ~|a|a|a|a|a?

点击查看代码
#include <cstdio>
#include <cstring>
#include <vector>
#include <cassert>
#include <algorithm>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#endif
typedef long long LL;
int n, pal[1 << 25];
char buf[1 << 25], a[1 << 25];
void manacher() {
	for (int i = 1, mid = 0, r = 0; i <= n; i++) {
		if (i <= r) pal[i] = min(pal[mid * 2 - i], r - i + 1);
		while (a[i - pal[i]] == a[i + pal[i]]) ++pal[i];
		if (i + pal[i] - 1 > r) r = i + pal[mid = i] - 1;
	}
}
int main() {
	scanf("%s", buf);
	int len = strlen(buf);
	a[0] = '~';
	a[++n] = '|';
	for (int i = 0; i < len; i++) a[++n] = buf[i], a[++n] = '|';
	a[++n] = '?';
	manacher();
	printf("%d\n", *max_element(pal + 1, pal + n + 1) - 1);
	return 0;
}

大致思路是,记当前右端点最右的回文串的右端点是 \(r\),中点是 \(mid\),那么如果 \(mid<i\leq r\)\(i\) 的回文串长度至少是它的对称,\(2mid-i\)。从这个半径开始暴力扩展。

posted @ 2022-11-07 15:12  caijianhong  阅读(11)  评论(0编辑  收藏  举报