1. #pragma GCC optimize(2)
    2. #include <iostream>
    3. #include <functional>
    4. #include <algorithm>
    5. #include <vector>
    6. #include <deque>
    7. #include <stdlib.h>
    8. #include <string.h>
    9. using namespace std;
    10. class Solver {
    11. // 野路子
    12. static const int MAXN = 20000 + 10;
    13. int dp[MAXN] = {};
    14. void zeroOnePack(int v, int w) {
    15. for (int j = V; j >= v; j--)
    16. dp[j] = max(dp[j], dp[j - v] + w);
    17. }
    18. void completePack(int v, int w) {
    19. for (int j = v; j <= V; j++)
    20. dp[j] = max(dp[j], dp[j - v] + w);
    21. }
    22. void multiPack(int v, int w, int s) {
    23. if (v * s >= V) {
    24. completePack(v, w);
    25. } else {
    26. for (int k = 1; k <= s; k <<= 1) {
    27. zeroOnePack(v * k, w * k);
    28. s -= k;
    29. }
    30. if (s) zeroOnePack(v * s, w * s);
    31. }
    32. }
    33. public:
    34. int N, V;
    35. void f() {
    36. cin >> N >> V;
    37. for (int i = 1; i <= N; i++) {
    38. int v, w, s;
    39. cin >> v >> w >> s;
    40. multiPack(v, w, s);
    41. }
    42. cout << dp[V] << endl;
    43. }
    44. };
    45. // 单调队列优化版本
    46. /*
    47. 总共 N 个物品,背包体积为 V
    48. 每个物品的体积是 v,价值是 w,数量是 s
    49. 思路:
    50. 原始方程:f[i][j] = max(f[i - 1][j], f[i - 1][j - kv] + kw) (0 <= k <= j/v)
    51. 一维优化后:f[j] = max(g[j - kv] + kw) (0 <= k <= j / v)
    52. 其实可以分组,即对每一个数据为 v, w, s 的物品,进行枚举时,利用 j % v,把 V 分成 v 组
    53. 假设对于首项为0的那组:
    54. f[0] = f[0]
    55. f[v] = f[v], f[v - v] + w = f[v], f[0] + w
    56. f[2v] = f[2v], f[2v - v] + w, f[2v - 2v] + 2w = f[2v], f[v] + w, f[0] + 2w
    57. ...
    58. f[kv] = f[kv], f[(k - 1)v] + w, ..., f[0] + kw
    59. 可以转换成
    60. f[0] - 0w = f[0]
    61. f[v] - 1w = f[v] - w, f[0]
    62. f[2v] - 2w = f[2v] - 2w, f[v] - w, f[0]
    63. ...
    64. f[kv] - kw = f[kv] - kw, f[(k-1)v] - (k-1)w, ..., f[0]
    65. 这样就可以用单调队列去维护了,只要在最后的结果那加 kw 就好
    66. */
    67. class Solver2 {
    68. static const int MAXN = 20000 + 5;
    69. struct Node {
    70. int pos, val;
    71. } q[MAXN];
    72. int dp[MAXN] = {};
    73. int N, V;
    74. void multiPack(int v, int w, int s) {
    75. for (int i = 0; i < v; i++) {
    76. int hh = 0, tt = 0, stop = (V - i) / v;
    77. for (int k = 0; k <= stop; k++) {
    78. int val = dp[k * v + i] - k * w;
    79. while (hh < tt && q[tt - 1].val <= val) tt--;
    80. if (hh < tt && q[hh].pos < k - s ) hh++;
    81. q[tt].val = val, q[tt++].pos = k;
    82. dp[k * v + i] = q[hh].val + k*w;
    83. }
    84. }
    85. }
    86. public:
    87. void f() {
    88. cin >> N >> V;
    89. int v, w, s;
    90. for (int i = 0; i < N; i++) {
    91. cin >> v >> w >> s;
    92. multiPack(v, w, s);
    93. }
    94. cout << dp[V] << endl;
    95. }
    96. };
    97. int main() {
    98. Solver2 s;
    99. s.f();
    100. }