[HEOI2013]Eden 的新背包问题

13 篇文章 1 订阅
题面

原题过于繁复,这里口述,多重背包,多次询问,每次询问的背包容量不一样,并且每次询问会规定一个物品不能选(这个规定的物品每次询问都会改变)。

题解

首先考虑对询问的两个要求,容量不一样很好处理,因为DP跑背包的过程中本来就会记录不同容量时的答案。

对于规定一个物品不能选怎么处理呢?不计算这一个物品,需要计入答案的物品就被分成了编号比这个物品小的物品集合和编号比这个物品大的物品集合,可以直接双向跑背包,f表示从前到后的,g表示从后到前的,然后把两个背包合并。

因为这是个多重背包,还需要套一个二进制拆分。

#include<bits/stdc++.h>
using namespace std;
namespace fastio{
	template<typename tn> void read(tn &a){
	    tn x=0,f=1;char c=' ';
	    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	    for(;isdigit(c);c=getchar() ) x=x*10+c-'0';
	    a=x*f;
	}
	template<typename tn> void print(tn a){
	    if(a<0) putchar('-'),a=-a;
	    if(a>9) print(a/10);
	    putchar(a%10+'0');
	}
};
using namespace fastio;
int n,q;
const int N=2e4+5;
const int M=1e3+5;
int a,b,c;
int w[N],v[N],cnt;
int f[N][M],g[N][M];
int l[N],r[N]; 
int main(){
	read(n);
	for(int i=0;i<n;i++){
		read(a),read(b),read(c);
		for(int j=1;j<=c;j<<=1){
			c-=j;
			v[++cnt]=j*a,w[cnt]=j*b;
		}
		if(c) v[++cnt]=c*a,w[cnt]=c*b;
		l[i]=cnt+1;
		r[i]=l[i-1]-1;
	}
	for(int i=1;i<=cnt;i++)
		for(int j=1;j<M;j++){ 
			if(j>=v[i]) f[i][j]=max(f[i-1][j],f[i-1][j-v[i]]+w[i]);
			else f[i][j]=f[i-1][j];
		} 
	for(int i=cnt;i>=1;i--)
		for(int j=1;j<M;j++)
			if(j>=v[i]) g[i][j]=max(g[i+1][j],g[i+1][j-v[i]]+w[i]);
			else g[i][j]=g[i+1][j];
	read(q);
	while(q--){
		int d,e;
		read(d);
		read(e);
		int ans=0;
		for(int i=0;i<=e;i++)
			ans=max(ans,f[r[d]][i]+g[l[d]][e-i]);
		printf("%d\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值