Manacher算法求回文半径
这篇讲的比较好,准备一个模板,做题的时候用。
void manacher() { int mx = 0, id = 0; for (int i = 1; i <= n; i++) { if (mx > i) p[i] = min(p[id * 2 - i], mx - i); else p[i] = 1; while (a[i + p[i]] == a[i - p[i]]) p[i]++; if (mx < p[i] + i) { mx = p[i] + i; id = i; } } }
这个初始化的时候是从1开始的
for (int i = 1; i <= n; i++) { a[i * 2 - 1] = str[i]; a[i * 2] = -1; }
其中p表示回文半径,str是原串,a表示添加字符之后的串
两个例题:
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 20010; char str[maxn], a[maxn<<1]; int p[maxn<<1], L[maxn<<1], R[maxn<<1]; int n; void manacher() { int mx = 0, id = 0; for (int i = 1; i <= n; i++) { if (mx > i) p[i] = min(p[id * 2 - i], mx - i); else p[i] = 1; while (a[i + p[i]] == a[i - p[i]]) p[i]++; if (mx < p[i] + i) { mx = p[i] + i; id = i; } } } bool solve() { for (int i = 1; i <= L[0]; i++) { for (int j = 1; j <= R[0]; j++) { int l = L[i] + 1; int r = R[j] - 1; if (r - l <= 0) continue; int mid = (l + r) / 2; if (p[mid] >= r - mid + 1) return true; } } return false; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%s", str + 1); n = strlen(str + 1); for (int i = 1; i <= n; i++) { a[i * 2 - 1] = str[i]; a[i * 2] = '#'; } n = n * 2 - 1; a[0] = '$'; a[n + 1] = '@'; manacher(); memset(L, 0, sizeof(L)); memset(R, 0, sizeof(R)); for (int i = 1; i <= n; i++) { int l = i - p[i] + 1; int r = i + p[i] - 1; if (l == 1) L[++L[0]] = r; if (r == n) R[++R[0]] = l; } if (solve()) puts("Yes"); else puts("No"); } return 0; }
#include <cstdio> #include <iostream> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> using namespace std; typedef long long LL; const int maxn = 100010; int str[maxn], a[maxn<<1]; int p[maxn<<1]; int n; void manacher() { int mx = 0, id = 0; for (int i = 1; i <= n; i++) { if (mx > i) p[i] = min(p[id * 2 - i], mx - i); else p[i] = 1; while (a[i + p[i]] == a[i - p[i]]) p[i]++; if (mx < p[i] + i) { mx = p[i] + i; id = i; } } } void print() { for (int i = 1; i <= n; i++) printf("%d ", p[i]); } int main() { int T; int kase = 0; scanf("%d", &T); while (T--) { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &str[i]); for (int i = 1; i <= n; i++) { a[i * 2 - 1] = str[i]; a[i * 2] = -1; } int m = n; n = n * 2 - 1; a[0] = -5; a[n + 1] = -8; manacher(); int ans = 0; for (int i = 2; i <= n; i += 2) p[i] /= 2; for (int i = 2; i <= n; i += 2) { if (p[i] * 3 < ans) continue; for (int j = p[i]; j * 3 >= ans; j--) { if (p[i + j * 2] >= j) { ans = max(ans, j * 3); break; } } } printf("Case #%d: %d\n", ++kase, ans); } return 0; }