看题解都是单调队列,其实那个单调队列优化的过程,就是在一个单调队列优化多重背包的过程。因为我们第i天是可以买一定数量的股票,或者卖一定数量。但是直接枚举一个一个股票的加是复杂度爆炸。f[i][j],表示第i天拥有j个股票的最大收益,在这个地方其实看着就很多重背包好吗!!!!!板子,大板子!!!所以就在买多少/卖多少股票的部分可以用二进制去优化多重背包,这样子就变成log的时间,其他题解的单调队列实则就是个单调队列优化多重背包的过程,都是可以的。知道是多重背包后就随便套板子就可以了。
int T, maxP, W;
struct {
int ap, bp, as, bs;
}node[max_];
int f[max_][max_], maxv[max_][max_];
signed main() {
register int i, j, multipal;
T = read(), maxP = read();
W = read();
for ( i = 1; i <= T; i++) {
node[i].ap = read();
node[i].bp = read();
node[i].as = read();
node[i].bs = read();
}
memset(f, 128, sizeof(f));
for ( i = 0; i <= T; i++)f[i][0] = 0;
for ( i = 0; i <= maxP; i++)maxv[0][i] = -INF;
maxv[0][0] = 0;
int ans = -INF;
for ( i = 1; i <= T; i++) {
//卖
int num = node[i].bs;
for ( multipal = 0; num - (1 << multipal) >= 0; multipal++) {
int bat = (1 << multipal);
num -= bat;
int pay = bat * node[i].bp;
for ( j = 0; j + bat <= maxP; j++) {
int v = -INF; if (i - W - 1 >= 0)v = maxv[i - W - 1][j + bat];
v = max(v, f[i][j + bat]);
f[i][j] = max(f[i][j], v + pay);
}
}
if (num) {
int bat = num;
int pay = bat * node[i].bp;
for ( j = 0; j + bat <= maxP; j++) {
int v = -INF; if (i - W - 1 >= 0)v = maxv[i - W - 1][j + bat];
v = max(v, f[i][j + bat]);
f[i][j] = max(f[i][j], v + pay);
}
}
//买
num = node[i].as;
for ( multipal = 0; num - (1 << multipal) >= 0; multipal++) {
int bat = (1 << multipal);
num -= bat;
int pay = bat * node[i].ap;
for ( j = maxP; j >= bat; j--) {
int v = -INF; if (i - W - 1 >= 0)v = maxv[i - W - 1][j - bat];
v = max(v, f[i][j - bat]);
f[i][j] = max(f[i][j], v - pay);
}
}
if (num) {
int bat = num;
int pay = bat * node[i].ap;
for ( j = maxP; j >= bat; j--) {
int v = -INF; if (i - W - 1 >= 0)v = maxv[i - W - 1][j - bat];
v = max(v, f[i][j - bat]);
f[i][j] = max(f[i][j], v - pay);
}
}
for ( j = 0; j <= maxP; j++) {
maxv[i][j] = max(maxv[i - 1][j], f[i][j]); ans = max(ans, maxv[i][j]);
}
}
printf("%lld\n", ans);
return 0;
}