洛谷p2569 二进制优化多重背包 dp

看题解都是单调队列,其实那个单调队列优化的过程,就是在一个单调队列优化多重背包的过程。因为我们第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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值