Focus on yourself, m|

wscqwq

园龄:2年粉丝:2关注:3

多重背包单调队列

考虑思考一下 f 最暴力的转移。设 v,w,s 为当前处理的物品的体积、价值、数量。然后体积 jmodv=r。显然是 f[i][j]=minf[i1][j],f[i1][jv]+w,f[i1][j2v]+2w,f[i1][j3v]+3w,,f[i1][jsv]+sw。然后写一下下一项 f[i][jv]=minf[i1][jv],f[i1][j2v]+w,f[i1][j3v]+2w,f[i1][j4v]+3w,,f[i1][j(s+1)v]+sw。以此类推,发现每一项都在前面少了一项,最后一项当然是 f[i][r]。发现这些递推式都是由 f[i1] 这一层的所有值构成的,可以看作长度为 s+1 的滑动窗口。我们可以直接按照余数 0r<v 来处理,一类一个滑动窗口处理即可。时间复杂度恰好是循环 n 次,每次都是以余数遍历,仔细分析内部两重循环其实是 O(m),总的就是 O(nm),相比于二进制优化又有了提升。

#include<cstdio>
#define max(x,y) ((x)>(y)?(x):(y))
const int N=20001;
int n,m,f[N],g[N],q[N]; 
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;++i){
		int v,w,s;
		scanf("%d%d%d",&v,&w,&s);
		for(int j=0;j<=m;++j)g[j]=f[j];
		for(int j=0;j<v;++j){//注意这个两重循环是 O(m),因为每个余数都枚举到了,只是整合成一块了。
			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)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;
			}
		}
	}
	printf("%d",f[m]);
	return 0;
}

本文作者:wscqwq

本文链接:https://www.cnblogs.com/wscqwq/p/17323384.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wscqwq  阅读(42)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起