单调队列优化多重背包
就是按照 % 体积的余数来分组,每组单调队列优化。
直接上模板好了。
1 #include <bits/stdc++.h> 2 3 typedef long long LL; 4 const int N = 100010; 5 6 int n, V, cnt[N], cost[N]; 7 LL f[2][N], val[N], p[N], top, head; 8 9 inline void Max(LL &a, const LL &b) { 10 a < b ? a = b : 0; 11 return; 12 } 13 14 int main() { 15 16 freopen("bag.in", "r", stdin); 17 freopen("bag.out", "w", stdout); 18 19 scanf("%d%d", &n, &V); 20 for(int i = 1; i <= n; i++) { 21 scanf("%d%d%lld", &cnt[i], &cost[i], &val[i]); 22 } 23 LL ans = 0; 24 for(int i = 1; i <= n; i++) { 25 for(int j = 0; j < cost[i]; j++) { 26 p[head = top = 1] = 0; 27 for(int g = 1; g * cost[i] + j <= V; g++) { 28 while(g - p[head] > cnt[i]) head++; 29 int t = p[head]; 30 Max(f[i & 1][g * cost[i] + j], f[(i - 1) & 1][t * cost[i] + j] + (g - t) * val[i]); 31 while(top >= head && f[(i - 1) & 1][cost[i] * p[top] + j] + (g - p[top]) * val[i] <= f[(i - 1) & 1][g * cost[i] + j]) { 32 top--; 33 } 34 p[++top] = g; 35 } 36 } 37 for(int j = 0; j <= V; j++) { 38 Max(ans, f[i & 1][j]); 39 f[(i - 1) & 1][j] = f[i & 1][j]; 40 } 41 } 42 43 printf("%lld\n", ans); 44 return 0; 45 } 46 /* 47 5 50 48 1 1 7 49 2 1 4 50 2 4 1 51 3 1 3 52 2 3 8 53 -------------- 42 54 */
重写一下,这个东西还是先按照经典二维数组来考虑,如下图:
这是用完了i-1类物品,开始用i类物品的时候,假设i类物品单个体积为3,那么发现按照3的余数分组的话,只会有每组之内的转移。不会跨组。在单个组内考虑体积为j时的情况,只有它前面cnt个可以转移过来,是个滑动窗口。每向前一个,就要加上一个价值。于是可以单调队列。具体看代码。