题目链接 Hrbust 2363
来源 “科林明伦杯”哈尔滨理工大学第七届程序设计团队赛 Problem J
题意 给出一个长度为$1e6$的字符串,求最小可重回文子串覆盖数量
首先Manacher预处理出以$s[i]$为首字母的回文子串的长度的最大值
然后求出包含$s[i]$的回文子串的能延伸到的最左端的位置
DP即可
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) const int N = 2e6 + 10; char a[N], s[N]; int dp[N], c[N], d[N], f[N], g[N]; int T, n, m, r, p, cnt, ans, now, ca = 0; vector <int> v[N]; void up(int &x, int y){ if (x < y) x = y;} int main(){ scanf("%d", &T); while (T--){ scanf("%s", a + 1); n = strlen(a + 1); rep(i, 1, n) s[i << 1] = a[i], s[i << 1 | 1] = ‘#‘; s[0] = ‘$‘, s[1] = ‘#‘, s[m = (n + 1) << 1] = ‘@‘; r = 0, p = 0, f[1] = 1; rep(i, 2, m - 1){ for (f[i] = r > i ? min(r - i, f[p * 2 - i]) : 1; s[i - f[i]] == s[i + f[i]]; f[i]++); if (i + f[i] > r) r = i + f[i], p = i; } rep(i, 0, m) g[i] = 0; rep(i, 2, m - 1) up(g[i - f[i] + 1], i + 1); rep(i, 1, m) up(g[i], g[i - 1]); ans = 0; cnt = 0; for (int i = 2; i < m; i += 2){ ++cnt; c[cnt] = g[i] - i; } rep(i, 1, n) c[i] = i + c[i] - 1; rep(i, 1, n) d[i] = i; rep(i, 1, n) d[c[i]] = min(d[c[i]], i); dec(i, n - 1, 1) d[i] = min(d[i], d[i + 1]); rep(i, 0, n + 1) dp[i] = 1e9; dp[0] = 0; rep(i, 1, n) dp[i] = min(dp[i], dp[d[i] - 1] + 1); printf("Case #%d: %d\n", ++ca, dp[n]); } return 0; }