HDU 5677 ztr loves substring
Manacher+二维费用多重背包 二进制优化
这题是一眼标算....先计算出每个长度的回文串有几种,然后用二维费用的多重背包判断是否有解。
多重背包做的时候需要二进制优化。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int maxn = 300; int N, p[maxn]; char str[maxn], b[maxn]; int cnt[maxn]; int n, k, L; bool dp[maxn][maxn]; void init() { int i; for (i = 0; str[i]; i++) b[2 * i + 1] = '#', b[2 * i + 2] = str[i]; N = 2 * i + 1; b[0] = '$', b[N] = b[N + 1] = '#'; } void solve() { int i, id, max = 0; for (i = 1; i <= N; i++) { p[i] = i < max ? std::min(max - i, p[2 * id - i]) : 1; while (b[i + p[i]] == b[i - p[i]]) ++p[i]; if (i + p[i] > max) max = i + p[i], id = i; cnt[p[i] - 1]++; } } int main() { int T; scanf("%d", &T); while (T--) { memset(dp, 0, sizeof dp); dp[0][0] = 1; memset(cnt, 0, sizeof cnt); scanf("%d%d%d", &n, &k, &L); while (n--){ scanf("%s", str); init(); solve(); } for (int i = 100; i >= 1; i--) cnt[i] = cnt[i] + cnt[i + 2]; for (int i = 100; i >= 1; i--) { if (cnt[i] == 0) continue; int val = i, num = cnt[i]; int t = 1; while (num) { if (num > t) { int tmp_val = val*t; for (int d = L; d >= 0; d--) { for (int f = k; f >= 0; f--) { if (dp[d][f] == 0) continue; if (d + tmp_val <= L&&f + t <= k) dp[d + tmp_val][f + t] = 1; } } num = num - t; t = t * 2; } else { int tmp_val = val*num; for (int d = L; d >= 0; d--) { for (int f = k; f >= 0; f--) { if (dp[d][f] == 0) continue; if (d + tmp_val <= L&&f + num <= k) dp[d + tmp_val][f + num] = 1; } } num = 0; } } } if (dp[L][k]) printf("True\n"); else printf("False\n"); } return 0; }