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
说明
Delete the third course and the final score is
备注:
1≤ n≤ 105
0≤ k < n
1≤ s[i],c[i] ≤ 103
题意:删除K组,使得满足求和方程最大。
二分:一般这里的二分讲的是一直二分出答案,知道该答案满足条件的误差范围,一般是需要我们通过题目给出的信息,例如:公式,那么我们就需要应用公式加以变形成好计算的。
解题思路: 考虑分数规划 二分答案,假设当前二分了一个值D,我们要判断是否存在一个方案使得总绩点>=D ,>=D, >= ,即>=0,
于是选前 k 个最小的删了就行了。为什么删掉前k个最小的就可以了,因为我们是判断是否存在一个方案满足条件(总绩点>=D),故只需最大的方案满足就行,要是说任意个方案满足,则需最小的方案满足。
顺便说下,假如题目要求精度误差不超过1e-5,答案不超过1e10,那么一般60次就行了。
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define INF 0x3f3f3f3f
const double EPS=1e-10;
const int maxn=1e5+10;
double S[maxn],C[maxn],item[maxn];
int n,k;
bool OK(double judge)
{
for(int i=1;i<=n;i++)
{
item[i]=C[i]-judge*S[i];///最终推导出来的目标式子
}
sort(item+1,item+1+n);
double sum=0;
for(int i=1;i<=k;i++) ///把前k大的数加起来
sum+=item[n-i+1];
return sum>=0;
}
void solve()
{
double left=0.0,right=INF;
while(right-left>1e-8)
{
double mid=(right+left)/2.0;
if(OK(mid)) left=mid; ///存在一个方案使得总绩点>=D,说明二分出来的不够大,
///所以需要往后二分
else right=mid; ///说明二分的答案太大,所以需要往前找
// printf("mid=%lf\n",mid);
}
printf("%.7lf\n",right);
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
k=n-k; ///预处理,变成在n个中找出K个使得价值最大
for(int i=1;i<=n;i++)
scanf("%lf",&S[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&C[i]),C[i]*=S[i];
solve();
}
}
我的标签:做个有情怀的程序员。