题目
今年有 n 场 ACM-ICPC 竞赛,小明每场都有资格参加。第 i 场竞赛共有 b[i] 道题。小明预测第 i 场他能做出 a[i] 道题。为了让自己看着更“大佬”一些,小明想让自己平均做出的题数越大越好,也就是最大化大佬度,大佬度的定义如下:
为了达到这个目的,小明决定放弃 k 场比赛的参赛资格。请求出最大的大佬度。
例如有 3 场小型比赛,题数分别是 5 题、1 题、6 题,小明预测自己分别能做出 5 题、0题、2题。如果每场都参加,那么大佬度是 ,看着不怎么大佬。不过,如果放弃第 3 场比赛,那么大佬度就是 ,看着更加大佬了。
Input
输入测试文件含有多组测试,每组有 3 行。第一行有 2 个整数, 1 ≤ n ≤ 1000 和 0 ≤ k < n。第二行有 n 个整数,即每个 a[i]。第三行含有 n 个正整数 b[i]。保证 0 ≤ a[i] ≤ b[i] ≤ 1, 000, 000, 000。文件末尾由 n = k = 0 标识,并且不应该被处理。
Output
对于每组测试数据,输出一行整数,即放弃 k 场比赛后可能的最高大佬度。大佬度应该舍入到最近的整数。
Sample Input
3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0
Sample Output
83
100
Hint
为了避免舍入误差带来的二义性,所有答案与除法边界相差至少 0.001 (例如答案永远不可能出现 83.4997)。
首先第一个难点就是要想到转化的公式,我们可以设定所选的题目大佬度大于等于x
(sum a_i)/(sum b_i)> = x
<=> sum a_i> = sum(x * b_i)
<=> sum(a_i - x * b_i)> = 0。
我们为每个i计算c_i = a_i - x * b_i,c_i和大于等于0
在筛选之前我们先算出每个c_i,然后排序后去掉k个,将剩下的相加,如果和大于等于0说明x是可行的
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
int n = sc.nextInt();
int k = sc.nextInt();
if(n == 0 && k == 0) break;
int [] a = new int [n];
int [] b = new int [n];
for(int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
for(int i = 0; i < n; i++) {
b[i] = sc.nextInt();
}
double min = 0;
double max = 1;
while(max - min > 0.0001){
double mid = (max + min) / 2;
if(f(a, b, k, mid)) min = mid;
else max = mid;
}
if(f(a, b, k, max)) System.out.println((int)Math.round(max * 100));
else System.out.println((int)Math.round(min * 100));
}
sc.close();
}
public static boolean f(int [] a, int [] b, int k, double x) {
double res = 0;
double [] y = new double [a.length];
for(int i = 0; i < a.length; i++) {
y[i] += (a[i] - x * b[i]);
}
Arrays.sort(y);
for(int i = a.length - 1; i >= k; i--) {
res += y[i];
}
return res >= 0;
}
}