第八届“英拿科技杯”上海高校金马程序设计联赛暨东华大学邀请赛

第八届“英拿科技杯”上海高校金马程序设计联赛暨东华大学邀请赛

仪表盘所有提交榜单

I. 孤星

单点时限: 2.0 sec

内存限制: 512 MB

𝑛(1≤103) 个干员,每个干员工资为 𝑤𝑖(1≤𝑤𝑖≤105),贡献值为 𝑣𝑖(1≤𝑣𝑖≤102)。

给出 𝑚(1≤𝑚≤105)次询问,每次询问:当你能承受的总工资为 𝑊(0≤𝑊≤109) 时,能收获最大的贡献值是多少。

输入格式

第一行,两个整数 𝑛,𝑚。

接下来 𝑛 行,每行两个整数 𝑤𝑖,𝑣𝑖,表示每个干员的工资和贡献值。

接下来𝑚行,每行一个数 𝑊,表示单次询问中的可以承受的总工资。

输出格式

输出共𝑚行,每行一个数表示你的答案。

样例

input

4 3
1 2
2 1
1 1
2 3
5
1
0

output

6
2
0

 思路:这个题目真的让我对dp的理解加深了,其实这个就是一个大容量背包的问题,由于容量大,然后价值小,所以就可以考虑把下标和值调换一下,变成求一个价值最大为j的时候的最小的背包的总量dp[j]的问题,这样的话我们进行一次打表,之后的询问就可以O(logn)直接查询。这里要注意的就是我们这里求最小的问题的dp数组并不是一个递增的数组,原因就是因为不是每一个值都能往前倒到0,只有dp【0】为0的时候我们才能进行最小更新,所以我们进行需要进行一个后缀最小值处理,这样的话我们就可以在查询的时候减少时间复杂度。

#include "bits/stdc++.h"
using namespace std;
const int N = 1e9 + 3;
long long  w[2000], v[2000], dp[100010];
#define Inf 1000000005
//map<long long, long long> dp;
int main(){
	int n, m;
	cin>>n>>m;
	for(int i = 1; i <= n; i ++){
		cin>>w[i]>>v[i];
	}
	fill(dp, dp + 100010, Inf);
//		memset(dp, 0, sizeof(dp));
		dp[0] = 0;
		for(int i = 1; i <= n; i ++){
		for(int j = 100010; j >= 0; j --){
			dp[j] = dp[j];
			if(j - v[i] >= 0){
				dp[j] = min(dp[j], dp[j - v[i]] + w[i]);
			}
			
		}
	}
	long  long W;
//	sort(dp, dp + 100010);
	for (int i = 100000; i >= 0; i--) dp[i] = min(dp[i], dp[i + 1]);
	for(int k = 0; k < m; k ++){
		cin>>W;	

	long long  *ans = upper_bound(dp, dp + 100009, W);
		if(ans - dp == 0) cout<<0<<endl;
		else 
		cout<<ans - dp - 1<<endl; 

	}
	
	return 0;
}

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小竹子14

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值