题目描述
小咪是一个土豪手办狂魔,这次他去了一家店,发现了好多好多(n个)手办,但他是一个很怪的人,每次只想买k个手办,而且他要让他花的每一分钱都物超所值,即:买下来的东西的总价值/总花费=max。请你来看看,他会买哪些东西吧。
输入描述:
多组数据。
第一行一个整数T,为数据组数。
接下来有T组数据。
对于每组数据,第一行两个正整数n,k,如题。
接下来n行,每行有两个正整数ci,vi。分别为手办的花费和它对于小咪的价值。
输出描述:
对于每组数据,输出一个数,即能得到的总价值/总花费的最大值。精确至整数。
示例1
输入
1 5 1 1 2 2 3 3 4 4 5 5 6
输出
2
备注:
1≤T≤10
1≤n≤1e4
1≤k≤n
1≤ci,vi≤1e4
做法
这题可不能用“把价值/花费存在数组里,然后排序,选较大的k个”来求。这题是分子加分子,分母加分母,和分数加法还是有很大区别的。
这题可以用01分数规划,“01”表示选或不选,“分数”表示处理的对象是分数,“规划”表示选的方案。(模板题)
设存在一种方案,使得“ 买下来的东西的总价值/总花费 >= X ”。化简得,买下来的东西的总价值-X*总花费>=0。我们用二分枚举X,即可。
#include<bits/stdc++.h>
using namespace std;
int n,k,t;
struct ty{
int c,v;
long long tmp;
}a[10010];
bool cmp(ty a,ty b){
return a.tmp>b.tmp;
}
int isleft(int x){
for(int i=0;i<n;i++){
a[i].tmp=(long long)a[i].v-(long long)(x*a[i].c);
}
sort(a,a+n,cmp);
long long res=0;
int v=0,c=0;
for(int i=0;i<k;i++){
res+=a[i].tmp;
v+=a[i].v;
c+=a[i].c;
}
if(res>=0) return v/c;
else return -1;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d%d",&a[i].c,&a[i].v);
}
int l=0,r=1e8+5;
long long ans=0;
while(l+1<r){
int mid=l+(r-l)/2;
long long tmp=isleft(mid);
if(tmp!=-1) {
l=mid;
ans=tmp;
}
else r=mid;
}
cout<<ans<<endl;
}
}