主要思路
先二进制分解一下物品,然后做 01 背包的 DP,顺便用 bitset 维护是否转移即可。
代码
// P3423.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 3020; int n, bi[MAX_N], ci[MAX_N], space[MAX_N], id[MAX_N], value[MAX_N], tot, ans[MAX_N], dp[MAX_N * 10]; int limit; bitset<30300> stat[MAX_N]; int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%d", &bi[i]); for (int i = 1; i <= n; i++) scanf("%d", &ci[i]), id[i] = i; for (int i = 1; i <= n; i++) { int remain = ci[i], p = 1; while (p < remain) { space[++tot] = bi[i] * p, value[tot] = p, id[tot] = i; remain -= p, p <<= 1; } if (remain) space[++tot] = bi[i] * remain, value[tot] = remain, id[tot] = i; } scanf("%d", &limit); memset(dp, 0x3f, sizeof(dp)), dp[0] = 0; for (int i = 1; i <= tot; i++) for (int j = limit; j >= space[i]; j--) if (dp[j] > dp[j - space[i]] + value[i]) stat[i][j] = true, dp[j] = dp[j - space[i]] + value[i]; printf("%d\n", dp[limit]); int curt = limit; for (int i = tot; i >= 1; i--) if (stat[i][curt]) curt -= space[i], ans[id[i]] += value[i]; for (int i = 1; i <= n; i++) printf("%d ", ans[i]); return 0; }