题目大意:给你n个珠宝,每个珠宝有一个价值vivi和重量wiwi,现在要选k个,使得∑vi∑wi∑vi∑wi最大,求这k个珠宝的编号。
解题思路:这题和洛谷P1750的题意是一样的,变化的仅是输出的东西和数据范围。此题数据范围是n≤100000n≤100000,所以O(nk)O(nk)的贪心是会超时的。
我们可以二分价值m,如果该价值可用,那么就一定有∑vi∑wi≥m∑vi∑wi≥m,我们把该式变形,得∑(vi−wi×m)≥0∑(vi−wi×m)≥0,于是每次以这个式子为关键字,对所有珠宝进行一次排序,然后判断前k个之和是否≥0≥0即可。时间复杂度O(nlog2n)O(nlog2n)。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define EPS 1e-9
int n,k;
struct wp{
int v,w,id;
double y;
bool operator <(const wp& rhs)const{return y>rhs.y;}
}a[2000001];
bool ok(double d){
for(int i=1;i<=n;++i)a[i].y=a[i].v-a[i].w*d;
sort(a+1,a+n+1);
double ans=0;
for(int i=1;i<=k;++i)ans+=a[i].y;
return ans>=0;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%d%d",&a[i].v,&a[i].w),a[i].id=i;
double l=0,r=1e13+1;
while(r-l>EPS){
double mid=(l+r)/2;
if(ok(mid))l=mid;else r=mid;
}
for(int i=1;i<=k;++i)printf("%d ",a[i].id);
printf("\n");
return 0;
}