處理出原串中每一個點爲中點的極長迴文串,這個用hash或者manacher都可,反正這裏不是複雜度瓶頸:(。那麼問題就變成了可重疊的線段覆蓋問題。
設 \(f[i]\) 表示已經徹底覆蓋 \(1-i\) 的最小代價
那麼取結束點在i的線段\([l,r](r == i)\)
\(f[i] = \min\{f[k] + 1\} (l - 1 \leq k < r)\)
用bit維護後綴\(\min\)便可c++
#include <bits/stdc++.h> using namespace std; typedef unsigned int uint; const int N = 100010; const uint base = 13131; char s[N]; uint h[N], pw[N], g[N]; int p[N], f[N], cnt, n; struct Node {int l, r;} a[N]; struct bit { int c[N]; #define lowbit(i) (i & -i) void clear() { memset(c, 0x3f, sizeof(c)); } void add(int x, int v) { for(int i = x; i; i -= lowbit(i)) c[i] = min(c[i], v); } int query(int x) { int ans = 0x3f3f3f3f; for(int i = x; i <= n + 1; i += lowbit(i)) ans = min(ans, c[i]); return ans; } } t; uint gethash(int l, int r) { return h[r] - h[l - 1] * pw[r - l + 1]; } uint getghash(int l, int r) { return g[l] - g[r + 1] * pw[r - l + 1]; } bool check(int l, int r) { return gethash(l, r) == getghash(l, r); } bool operator < (Node a, Node b) { return a.r < b.r; } int solve() { t.clear(); memset(f, 0x3f, sizeof(f)); sort(a + 1, a + cnt + 1); int cur = 1; t.add(1, 0); for(int i = 1; i <= n; ++i) { while(cur <= cnt && a[cur].r <= i) f[i] = min(f[i], t.query(a[cur++].l) + 1); t.add(i + 1, f[i]); } return f[n] - 1; } int main() { #ifndef ONLINE_JUDGE freopen("data.in","r",stdin); #endif while(~scanf("%s", s + 1)) { n = strlen(s + 1); pw[0] = 1; h[0] = g[n + 1] = 0; for(int i = 1; i <= n; ++i) { h[i] = h[i - 1] * base + s[i]; pw[i] = pw[i - 1] * base; } for(int i = n; i; --i) g[i] = g[i + 1] * base + s[i]; cnt = 0; for(int i = 1; i <= n; ++i) { p[i] = 0; int l = 1, r = min(i - 1, n - i); while(l <= r) { int mid = (l + r) >> 1; if(check(i - mid, i + mid)) l = mid + 1, p[i] = mid; else r = mid - 1; } a[++cnt] = (Node) {i - p[i], i + p[i]}; p[i] = 0; l = 0, r = min(i, n - i); while(l <= r) { int mid = (l + r) >> 1; if(check(i - mid + 1, i + mid)) l = mid + 1, p[i] = mid; else r = mid - 1; } if(p[i]) a[++cnt] = (Node) {i - p[i] + 1, i + p[i]}; } printf("%d\n", solve()); } } /* 處理出原串中每一個點爲中點的極長迴文串,那麼問題就變成了可重疊的線段覆蓋問題。 設 $f[i]$ 表示已經徹底覆蓋 $1-i$ 的最小代價 那麼取結束點在i的線段[l,r](r == i) f[i] = min{f[k] + 1} (l - 1 <= k < r) 用bit維護後綴min便可 */