POJ:2976-Dropping tests(二分平均值)

Dropping tests

Time Limit: 1000MS Memory Limit: 65536K
Total Submissions: 15508 Accepted: 5418

Description

In a certain course, you take n tests. If you get ai out of bi questions correct on test i, your cumulative average is defined to be 100*sum(ai)/sum(bi)

.

Given your test scores and a positive integer k, determine how high you can make your cumulative average if you are allowed to drop any k of your test scores.

Suppose you take 3 tests with scores of 5/5, 0/1, and 2/6. Without dropping any tests, your cumulative average is . However, if you drop the third test, your cumulative average becomes .

Input

The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 and 0 ≤ k < n. The second line contains n integers indicating ai for all i. The third line contains n positive integers indicating bi for all i. It is guaranteed that 0 ≤ ai ≤ bi ≤ 1, 000, 000, 000. The end-of-file is marked by a test case with n = k = 0 and should not be processed.

Output

For each test case, write a single line with the highest cumulative average possible after dropping k of the given test scores. The average should be rounded to the nearest integer.

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

To avoid ambiguities due to rounding errors, the judge tests have been constructed so that all answers are at least 0.001 away from a decision boundary (i.e., you can assume that the average is never 83.4997).


中文题意:

今年有 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 场比赛后可能的最高大佬度。大佬度应该舍入到最近的整数。

解题心得:

  1. 其实就是一个最大化平均值的问题,最大化平均值二分的一种经典应用,先假设答案为ans,如果100 * sum(ai) / sum(bi) > ans,那么按照这种大于/小于的关系式来二分答案,但是在运算的时候需要转化一下关系式,可以转换成:100 * sum(ai) > sum(bi) * ans,按照乘法的分配律可以写成100 * sum(ai) > sum(bi * ans),然后移项得到关系式:100 * sum(ai) - sum(bi * ans) > 0,然后按照减法的分配律可以写成sum(100 * ai - bi * ans) > 0,这样可以先得出100 * ai-bi * ans,然后降序排序,算出前n - k个是否大于0,然后以此二分就行了。

#include <algorithm>
#include <cstring>
#include <stdio.h>
using namespace std;
typedef long long ll;
const int maxn = 1010;
ll n,k,a[maxn],b[maxn];
double c[maxn];

void init() {
    for(int i=0;i<n;i++)
        scanf("%lld",&a[i]);
    for(int i=0;i<n;i++)
        scanf("%lld",&b[i]);
}

bool cmp(double a,double b) {
    return a > b;
}

bool checke(double va) {
    for(ll i=0;i<n;i++)
        c[i] = (double)a[i]*100.0 - va*b[i];
    sort(c,c+n,cmp);
    double sum = 0;
    for(int i=0;i<n-k;i++)
        sum += c[i];
    return sum >= 0;
}

double binary_search() {
    double l,r;
    l = 0, r = 1e18+100;
    for(int i=0;i<100;i++) {//为了保证精度问题直接循环100次
        double mid = (l + r) / 2.0;
        if(checke(mid))
            l = mid;
        else
            r = mid;
    }
    return l;
}

int main() {
    while(scanf("%lld%lld",&n,&k) && n|k) {
        init();
        double ans = binary_search();
        ll int_ans = (ans + 0.5);
        printf("%lld\n",int_ans);
    }
    return 0;
}
posted @ 2018-04-08 17:39  GoldenFingers  阅读(151)  评论(0编辑  收藏  举报