链接:https://www.nowcoder.com/acm/contest/143/A
来源:牛客网
题目描述
Kanade selected n courses in the university. The academic credit of the i-th course is s[i] and the score of the i-th course is c[i].
At the university where she attended, the final score of her is
Now she can delete at most k courses and she want to know what the highest final score that can get.
输入描述:
The first line has two positive integers n,k
The second line has n positive integers s[i]
The third line has n positive integers c[i]
输出描述:
Output the highest final score, your answer is correct if and only if the absolute error with the standard answer is no more than 10-5
示例1
输入
复制
3 1
1 2 3
3 2 1
输出
复制
2.33333333333
题意
给你n个课程的学分和绩点,然后你可以去掉其中的k个课程的学分和绩点,然后求最大的平均学分绩点
思路
遇到这题之前还没听过01分数规划是个什么玩意,然后去学习了一波
01分数规划指的是有n个二元组
,然后选择其中的
的元素来得到
的一类问题
那怎么解决这类问题呢,我们可以用二分的方法来解决,来二分答案,为什么能二分呢,当前有
其中 是我们假定的一个值,然后有 ,
如果是t是取k个元素中最优的答案,那么我们令 ,然后最 数组从小到大排序(因为我们的目标是和为0,和应该向0靠拢所以加前k个),那么前k个元素的和也就是0,但如果前k个元素的和大于0,这说明我们的答案偏大了,让二分的r=mid即可,反之和小于0让l=mid即可,这样就可以二分出答案,时间复杂度算上二分和排序为 ,回到这题上来,这题和01分数规划的描述相同, , ,往上套二分即可
#include <iostream>
#include <string>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <math.h>
using namespace std;
const int N=1e5+5;
double a[N],b[N];
double t[N];
int main()
{
int n,k;
while(scanf("%d%d",&n,&k)!=EOF)
{
for(int i=0;i<n;i++)
scanf("%lf",&b[i]);
double r=0;
for(int i=0;i<n;i++)
{
scanf("%lf",&a[i]);
if(r<a[i])
r=a[i];
a[i]*=b[i];
}
double l=0;
double mid;
while(fabs(l-r)>1e-9)
{
mid=(l+r)/2;
for(int i=0;i<n;i++) t[i]=mid*b[i]-a[i];
sort(t,t+n);
double sum=0;
for(int i=0;i<n-k;i++)
sum+=t[i];
if(sum<0)
l=mid;
else
r=mid;
}
printf("%.9lf\n",mid);
}
return 0;
}