题意:
Description
刘禅对学习的态度让太傅操碎了心。刘禅有n种课程要学习(礼、乐、射、御、书、数等等),每个课程有对应的重要程度s[i],刘禅估计了一下,机智的他算出了每个课程他最后能得到的分数c[i], 太傅给出了他最终成绩的计算公式:
现在他可以推迟k门课程,使得他剩下的n-k门课程的最终成绩尽量高,因为这样父皇才会让他出宫玩耍。机智的刘禅已经算出了答案,不过他想考考你。输出最高的不少于n-k门课程的最终成绩。
Input
多组数据,请读入到文件末尾(数据组数不超过10)第一行两个非负整数n, k(1≤ n≤ 1e5 , 0≤ k < n) 第二行n个正整数s[i] 第三行n个正整数c[i]1<=s[i],c[i]<=1000
Output
一个实数,四舍五入保留6位小数
Sample Input
3 1
1 2 3
3 2 1
Sample Output
2.333333
Hint
去掉最后一门课程即可。
(22+31)/(2+1)=7/3
思路:
01分数规划的裸题,利用二分找结果ans,会得到si✖️ci/ si = ans ,只要贪心求的前n - k大的si✖️ci - ans✖️si的和,大于等于0返回1,否则返回0
代码:
#include <stdio.h>
#include <algorithm>
using namespace std;
int a[100005], b[100005];
int n, k;
double t[100005];
bool whd(double A, double B) {
return A > B;
}
bool zcy(double val) {
double sum = 0;
for (int i = 0; i < n; i++) {
t[i] = a[i] - val * b[i];
}
sort(t, t + n, whd);
for (int i = 0; i < n - k; i++) {
sum += t[i];
}
if (sum >= 0) return 1;
return 0;
}
int main() {
while (scanf("%d%d", &n, &k) == 2) {
double minn = 0, maxx= 0;
for (int i = 0; i < n; i++) {
scanf("%d", &b[i]);
}
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
a[i] = a[i] * b[i];
if (maxx < a[i]) {
maxx = a[i];
}
}
double mid;
for (int i = 0; i < 80; i++) {
mid = (minn + maxx) / 2;
if (zcy(mid)) minn = mid;
else maxx = mid;
}
printf("%.6f\n", mid);
}
return 0;
}
如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢