题目大意
有N个东西,选择第i个东西价值为a[i],付出为b[i]。需要选择恰好M个东西来最大化∑a[i]/∑b[i]。
N<=10^5。结果保留三位小数。
01分数规划
如果∑a[i]/∑b[i]=c
则∑a[i]=∑b[i]∗c
则∑(a[i]−b[i]∗c)=0
因此我们可以设d[i]=a[i]-b[i]*c。c是不确定,不过发现c就是答案。因此我们二分c并计算d数组,由于结果大于等于0就代表这个答案是可行的,因此我们对d数组排序然后取前M个检验是否大于等于0。
注意
因为要保留三位小数,所以应当精确到四位,然后四舍五入。
参考程序
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxn=100000+10;
db d[maxn],a[maxn],b[maxn];
db p,l,r,mid,ans;
int i,j,k,t,n,m;
bool cmp(db a,db b){
return a>b;
}
int main(){
scanf("%d%d",&n,&m);
fo(i,1,n) scanf("%lf",&a[i]);
fo(i,1,n) scanf("%lf",&b[i]);
j=1;
fo(i,2,n)
if (a[i]/b[i]>a[j]/b[j]) j=i;
l=0;r=a[j]/b[j];
while (abs(r-l)>=0.0001){
mid=(l+r+0.0001)/2;
fo(i,1,n) d[i]=a[i]-mid*b[i];
sort(d+1,d+n+1,cmp);
p=0;
fo(i,1,m) p=p+d[i];
if (p>=0) l=mid;else r=mid-0.0001;
}
printf("%.3lf\n",l);
return 0;
}