链接: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个课程的学分和绩点,然后求最大的平均学分绩点 ∑ s [ i ] ∗ c [ i ] ∑ s [ i ] \frac{\sum s[i]*c[i]}{\sum s[i]} ∑s[i]∑s[i]∗c[i]
思路
遇到这题之前还没听过01分数规划是个什么玩意,然后去学习了一波
01分数规划指的是有n个二元组
{
v
i
,
c
i
}
\{ v_i,c_i \}
{vi,ci},然后选择其中的
k
k
k的元素来得到
m
a
x
(
∑
v
[
i
]
∑
c
[
i
]
)
max(\frac{\sum v[i]}{\sum c[i]})
max(∑c[i]∑v[i])的一类问题
那怎么解决这类问题呢,我们可以用二分的方法来解决,来二分答案,为什么能二分呢,当前有
t
=
∑
v
[
i
]
∑
c
[
i
]
t=\frac{\sum v[i]}{\sum c[i]}
t=∑c[i]∑v[i]
其中
t
t
t是我们假定的一个值,然后有
t
∑
c
[
i
]
=
∑
v
[
i
]
t\sum c[i]=\sum v[i]
t∑c[i]=∑v[i],
t
∑
c
[
i
]
−
∑
v
[
i
]
=
0
t\sum c[i]-\sum v[i]=0
t∑c[i]−∑v[i]=0
如果是t是取k个元素中最优的答案,那么我们令
t
[
i
]
=
t
∗
c
[
i
]
−
v
[
i
]
t[i]=t*c[i]-v[i]
t[i]=t∗c[i]−v[i],然后最
t
t
t数组从小到大排序(因为我们的目标是和为0,和应该向0靠拢所以加前k个),那么前k个元素的和也就是0,但如果前k个元素的和大于0,这说明我们的答案偏大了,让二分的r=mid即可,反之和小于0让l=mid即可,这样就可以二分出答案,时间复杂度算上二分和排序为
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n),回到这题上来,这题和01分数规划的描述相同,
v
[
i
]
=
s
[
i
]
∗
c
[
i
]
v[i]=s[i]*c[i]
v[i]=s[i]∗c[i],
c
[
i
]
=
s
[
i
]
c[i]=s[i]
c[i]=s[i],往上套二分即可
#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;
}