AcWing 6. 多重背包问题 III

//j-kv     是%v余数相同的点
//设余数是r
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 20010;
int n, m;
int f[N], g[N], q[N];
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i ++ ) {
        int v, w, s;
        cin >> v >> w >> s;
        memcpy(g, f, sizeof f);//存储上一层,因为会用到上一层的数数据
        for (int j = 0; j < v; j ++ ) {//余数 
            int hh = 0, tt = -1;//滑动窗口,队列
            for (int k = j; k <= m; k += v) { //表示每一个体积 
                if (hh <= tt && q[hh] < k - s * v)//当队列不空,而且已经滑出窗口 
                    hh ++ ;
                if (hh <= tt)//如果队列不空,更新当且最大值
                //最大值位队头元素
                //q[hh]对应最大值对应下标,基础值再加上收益
                //收益是指里面装了多少个第i个物品,多少个:k-q[hh]/v个,再乘价值 
                                    //中间空余了多少个第i个物品的体积    空余一个,就可以多放一个物品进来 
                    f[k] = max(f[k], g[q[hh]] + (k - q[hh]) / v * w);
                    //弹出没有用的元素       下标减去初始余数 
                    //当队列不空,而且队尾价值小于当前价值,队尾就没有意义,弹出 
                while (hh <= tt && g[q[tt]] - (q[tt] - j) / v * w <= g[k] - (k - j) / v * w)
                    tt -- ;
                q[ ++ tt] = k;//存每个体积 
            }
        }
    }
    cout << f[m] << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/QingyuYYYYY/p/11979220.html