单调队列优化多重背包

就是按照 % 体积的余数来分组,每组单调队列优化。

直接上模板好了。

 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 */
AC代码

重写一下,这个东西还是先按照经典二维数组来考虑,如下图:

 

这是用完了i-1类物品,开始用i类物品的时候,假设i类物品单个体积为3,那么发现按照3的余数分组的话,只会有每组之内的转移。不会跨组。在单个组内考虑体积为j时的情况,只有它前面cnt个可以转移过来,是个滑动窗口。每向前一个,就要加上一个价值。于是可以单调队列。具体看代码。

posted @ 2019-03-14 17:49  huyufeifei  阅读(221)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜