「HEOI2013」Eden的新背包问题

题目

传送门

题解

假设我们忽略物品 \(i\),那么所有的物品我们分成 \(1\text{~}i-1\) 的物品和 \(i+1\text{~}n\) 的物品这两个部分,在这两个部分里面选择容量不超过 \(e_i\) 的物品的最大价值。

那么我们考虑从 \(1\) 开始跑部分背包,从 \(n\) 开始往前跑部分背包。

\(dp1[i][j]\) 为在物品 \(1\text{~}i\) 中,选择容量不超过 \(j\) 的最大价值。

\(dp2[i][j]\) 为在物品 \(i\text{~}n\) 中,选择容量不超过 \(j\) 的最大价值。

这个应该是很好做的。

对于每一个询问我们有 \(d,e\),那么答案就是

\[\max\{dp1[d-1][i]+dp2[d+1][e-i]\mid 0\le i\le e\} \]

#include<cstdio>

template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T Fabs(const T x){return x>0?x:-x;}

const int MAXN=1e3;
const int MAXW=1e3;

int a[MAXN+5],b[MAXN+5],c[MAXN+5];

int dp1[MAXN+5][MAXW+5];
int dp2[MAXN+5][MAXW+5];

int n,q,d,e;

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d %d %d",&a[i],&b[i],&c[i]);
	for(int i=1;i<=n;++i)for(int k=0;k<=c[i];++k)for(int j=MAXW,siz=k*a[i];j>=siz;--j)
		dp1[i][j]=Max(dp1[i][j],dp1[i-1][j-k*a[i]]+k*b[i]);
	for(int i=n;i>=1;--i)for(int k=0;k<=c[i];++k)for(int j=MAXW,siz=k*a[i];j>=siz;--j)
		dp2[i][j]=Max(dp2[i][j],dp2[i+1][j-k*a[i]]+k*b[i]);
	scanf("%d",&q);
	while(q--){
		scanf("%d %d",&d,&e);++d;
		int ans=0;
		for(int i=0;i<=e;++i)ans=Max(ans,dp1[d-1][i]+dp2[d+1][e-i]);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2020-04-24 12:29  Arextre  阅读(97)  评论(0编辑  收藏  举报