【模板】Manacher
原题目:
luogu-P3805
简要描述:
模板题
cpp
copy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Author by Rainboy blog: https://rainboylv.com github : https://github.com/rainboylvx
* date: 2025-12-09 14:25:45
* oj: luogu-3805
* title: 【模板】Manacher
* description: 模板
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6+5;
int n,m;
int a[maxn];
constexpr int MAXN = 2e7+5; // 原始字符串最大长度
// Manacher 模板(不使用 std::string)
struct Manacher {
// 变换后长度上限:2*MAXN + 少量哨兵
static const int SZ = MAXN * 2 + 5;
char t[SZ]; // 变换后的字符串:^ # a # b # ... # $
int p[SZ]; // 半径数组(在 t 上的扩展长度)
int m = 0; // t 的实际长度(含终止符)
// 构造变换串并计算 p[]
// 输入:C 风格字符串 s(以 '\0' 结尾)
void build(const char *s) {
int n = (int)strlen(s);
int k = 0;
t[k++] = '&'; // 左哨兵,防止越界
t[k++] = '#';
for (int i = 0; i < n; ++i) {
t[k++] = s[i];
t[k++] = '#';
}
t[k++] = '^'; // 右哨兵
t[k] = '\0';
m = k;
// 初始化半径数组
// for (int i = 0; i < m; ++i) p[i] = 0;
memset(p,0,sizeof(p));
// Manacher 主循环
int center = 0, right = 0;
for (int i = 1; i < m - 1; ++i) {
int mirror = 2 * center - i;
if (i < right) p[i] = min(right - i, p[mirror]);
else p[i] = 1; // 长度至少是1
// 暴力扩展:安全因为有哨兵
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
// 更新中心与右边界
if (i + p[i] > right) {
center = i;
right = i + p[i];
}
}
}
// 获取最长回文子串,返回长度;通过引用参数 l,r 返回原串上的左闭右闭索引(0-based)
int longest(int &l, int &r) const {
int best_len = 0, best_center = 0;
for (int i = 1; i < m - 1; ++i) {
if (p[i]-1 > best_len) {
best_len = p[i]-1;
best_center = i;
}
}
if (best_len == 0) { l = 0; r = -1; return 0; }
// 将 t 中的位置映射回原串的索引
l = (best_center - best_len) / 2;
r = l + best_len - 1;
return best_len;
}
};
Manacher man;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
static char s[MAXN + 5];
if (scanf("%s", s) != 1) return 0; // 读取一个单词(竞赛常用)
// 若需读取整行(含空格),使用 fgets 或 fgets + 去除末尾换行
man.build(s);
int L, R;
int len = man.longest(L, R);
printf("%d\n", len);
return 0;
}