洛谷P2370 yyy2015c01 的 U 盘

158 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

yyy2015c01 的 U 盘

题目背景

在 2020 年的某一天,我们的 yyy2015c01 买了个高端 U 盘。

题目描述

你找 yyy2015c01 借到了这个高端的 U 盘,拷贝一些重要资料,但是你发现这个 U 盘有一些问题:

  1. 这个 U 盘的传输接口很小,只能传输大小不超过 LL 的文件。
  2. 这个 U 盘容量很小,一共只能装不超过 SS 的文件。

但是你要备份的资料却有很多,你只能备份其中的一部分。

为了选择要备份哪些文件,你给所有文件设置了一个价值 ViV_i,你希望备份的文件总价值不小于 pp

但是很快你发现这是不可能的,因为 yyy2015c01 的传输接口太小了,你只有花钱买一个更大的接口(更大的接口意味着可以传输更大的文件,但是购买它会花费更多的钱)。

注意:你的文件不能被分割(你只能把一个文件整个的传输进去,并储存在U盘中),

你放在 U 盘中文件的总大小不能超过 U 盘容量。

现在问题来了:你想知道,在满足 U 盘中文件价值之和不小于 pp 时,最小需要多大的接口。

输入格式

11 行,三个正整数 n,p,Sn,p,S 分别表示文件总数,希望最小价值 pp ,U 盘大小。

接下来 nn 行,每行两个正整数 Wi,ViW_{i},V_{i},表示第 ii 个文件的大小和价值。

输出格式

输出一个正整数表示最小需要的接口大小。

如果无解输出 No Solution!

样例 #1

样例输入 #1

3 3 5
2 2
1 2
3 2

样例输出 #1

2

样例 #2

样例输入 #2

2 3 505
1 2
500 1

样例输出 #2

500

样例 #3

样例输入 #3

3 3 2
2 2
1 2
3 2

样例输出 #3

No Solution!

样例 #4

样例输入 #4

4 5 6
5 1
5 2
5 3
1 1

样例输出 #4

No Solution!

提示

1n,Wi,S1031 \le n, W_i, S \le 10^31Vi1061 \leq V_i \leq 10^61p1091 \leq p \leq 10^9

数据较小,请勿乱搞。

样例解释 11:买一个大小为 22 接口,把物品 1122 放进U\text{U}盘。

样例解释 22:买一个大小为 500500 的接口。

样例解释 33:本来可以买大小为 22 的接口,可是 U 盘容量放不下足够的文件。

如果数据出现疏漏,请联系出题人 a710128

向本题主人公 yyy2015c01 同学致敬!

分析

这题是个经典的二分+dpdp,有个要注意的地方,传输大小不超过LL的文件的意思是所有不超过LL的文件都可以传输,而不是只能传输一个(雾)。然后就是个典型的0101背包问题,就是大小为ss的背包最多能装多少价值的物品,然后要注意要特判一下,只有小于LL的物品才能装进背包。然后就二分一下接口的LL,找出最小的L,当最大的wiw_i都无法满足的时候,说明无解。然后就没了。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string> 
#include <queue>
#include <vector>
#include <map>
#include <set>
#include <stack> 
#include <cmath>
#include <iomanip>
#define ll long long
#define AC return
#define Please 0
#define lowbit(x) x&(-x) 
using namespace std;
const int N=1010;
typedef pair<int,int>PII;
typedef unsigned long long ull; 
struct ob{
	int w,v;
}a[N];
int dp[N]; 
inline int read(){//快读 
	int x=0,f=1;char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=x*10+ch-'0'; 
		ch=getchar();
	}
	AC x*f;
}
int w[N],v[N];//w文件大小 v文件价值 
int n,p,s;//n数量 p总价值 s u盘容量 
bool check(int x){
	memset(dp,0,sizeof dp);
	for(int i=1;i<=n;i++){
		for(int j=s;j>=a[i].w;j--){
			if(a[i].w<=x){
				dp[j]=max(dp[j],dp[j-a[i].w]+a[i].v);
			}
		}
	}
	if(dp[s]>=p) return true;
	return false;
}
int main(){
	cin>>n>>p>>s;
	int maxn=0;
	for(int i=1;i<=n;i++){
		cin>>a[i].w>>a[i].v;
		maxn=max(maxn,a[i].w);
	}
	int l=0,r=maxn;
	if(!check(maxn)){
		cout<<"No Solution!"<<endl;
		return 0;
	}
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1; 
	}        
	cout<<l;                                             
	AC Please;
}

希望能帮到大家(QAQQAQ)!