预处理01背包

在这里插入图片描述
输入
输入第一行包含三个正整数n,m,t,代表商店物品的数量,鸡尾酒带的钱,和询问的次数。(n,m<=2000,t<=3000)

接下来n行,每行输入两个正整数,分别代表第i个物品在平常的价格ai和价值bi。(ai<=m, bi<=1e9)

接下来有t组询问,每组询问包含三个数字,x,c,d。代表某一天第x个物品参与“特别活动”,并且价格变为c,价值变为d。(c<=m,d<=1e9)

输出
对于每组询问,回答鸡尾酒那一天可以购买的物品最大价值和。
3 10 3
1 2
5 10
4 9
1 3 8
2 3 5
3 4 5

19
16
17
正反各预处理一遍01背包 O(n*m)
t组样例 只能O(m)

#include <bits/stdc++.h>
using namespace std;

#define rep(i,a,n) for (int i=a;i<=n;i++)
#define pb push_back
#define mp make_pair
#define IO ios::sync_with_stdio(false)
#define fi first
#define se second

typedef long long ll;
typedef pair<int,int> pii;
const int maxn=2e5+5;
const int maxm=1e6+5;
const ll INF=0x3f3f3f3f3f3f3f3f;
const ll mod=1e9+7;
 
ll w[2005],v[2005],ans1,ans2;
ll pre[2005][2005],suf[2005][2005];
int n,m,t,x,c,d;
int main(){
	cin>>n>>m>>t;
	rep(i,1,n){
		cin>>w[i]>>v[i];
	}
	for(int i=1;i<=n;i++){
		for(int j=0;j<=m;j++)
		if(w[i]<=j)
			pre[i][j]=max(pre[i-1][j],pre[i-1][j-w[i]]+v[i]);
		else
			pre[i][j]=pre[i-1][j];
	}
	for(int i=n;i>=1;i--){
		for(int j=0;j<=m;j++)
			if(w[i]<=j)
				suf[n-i+1][j]=max(suf[n-i][j],suf[n-i][j-w[i]]+v[i]);//背包装的第一个物品是原先第n个 
			else
				suf[n-i+1][j]=suf[n-i][j];
		
	}
	while(t--){
		ans1=0,ans2=0;
		cin>>x>>c>>d;
		for(int j=0;j<=m;j++)
			ans1=max(pre[x-1][j]+suf[n-x][m-j],ans1);	//不装当前第x个物品 n=3 x=2 装第一个 和 倒数第一个 
		for(int j=0;j<=m-c;j++)	//要当前第x个物品 背包空间腾出c 
		{
			ans2=max(pre[x-1][j]+suf[n-x][m-c-j],ans2);
		}
		cout<<max(ans1,ans2+d)<<endl;
	}
	
	return 0;
}

用到中间的pre,suf的dp值 所以else递推不能省略 否则会wa

如果直接求dp[n][m] dp方程可以不用管else递推

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值