#pragma GCC optimize(2)#include <iostream>#include <functional>#include <algorithm>#include <vector>#include <deque>#include <stdlib.h>#include <string.h>using namespace std;class Solver { // 野路子 static const int MAXN = 20000 + 10; int dp[MAXN] = {}; void zeroOnePack(int v, int w) { for (int j = V; j >= v; j--) dp[j] = max(dp[j], dp[j - v] + w); } void completePack(int v, int w) { for (int j = v; j <= V; j++) dp[j] = max(dp[j], dp[j - v] + w); } void multiPack(int v, int w, int s) { if (v * s >= V) { completePack(v, w); } else { for (int k = 1; k <= s; k <<= 1) { zeroOnePack(v * k, w * k); s -= k; } if (s) zeroOnePack(v * s, w * s); } }public: int N, V; void f() { cin >> N >> V; for (int i = 1; i <= N; i++) { int v, w, s; cin >> v >> w >> s; multiPack(v, w, s); } cout << dp[V] << endl; }};// 单调队列优化版本/* 总共 N 个物品,背包体积为 V每个物品的体积是 v,价值是 w,数量是 s思路: 原始方程:f[i][j] = max(f[i - 1][j], f[i - 1][j - kv] + kw) (0 <= k <= j/v) 一维优化后:f[j] = max(g[j - kv] + kw) (0 <= k <= j / v) 其实可以分组,即对每一个数据为 v, w, s 的物品,进行枚举时,利用 j % v,把 V 分成 v 组 假设对于首项为0的那组: f[0] = f[0] f[v] = f[v], f[v - v] + w = f[v], f[0] + w f[2v] = f[2v], f[2v - v] + w, f[2v - 2v] + 2w = f[2v], f[v] + w, f[0] + 2w ... f[kv] = f[kv], f[(k - 1)v] + w, ..., f[0] + kw 可以转换成 f[0] - 0w = f[0] f[v] - 1w = f[v] - w, f[0] f[2v] - 2w = f[2v] - 2w, f[v] - w, f[0] ... f[kv] - kw = f[kv] - kw, f[(k-1)v] - (k-1)w, ..., f[0] 这样就可以用单调队列去维护了,只要在最后的结果那加 kw 就好*/class Solver2 { static const int MAXN = 20000 + 5; struct Node { int pos, val; } q[MAXN]; int dp[MAXN] = {}; int N, V; void multiPack(int v, int w, int s) { for (int i = 0; i < v; i++) { int hh = 0, tt = 0, stop = (V - i) / v; for (int k = 0; k <= stop; k++) { int val = dp[k * v + i] - k * w; while (hh < tt && q[tt - 1].val <= val) tt--; if (hh < tt && q[hh].pos < k - s ) hh++; q[tt].val = val, q[tt++].pos = k; dp[k * v + i] = q[hh].val + k*w; } } }public: void f() { cin >> N >> V; int v, w, s; for (int i = 0; i < N; i++) { cin >> v >> w >> s; multiPack(v, w, s); } cout << dp[V] << endl; }};int main() { Solver2 s; s.f();}