4145:放弃考试 (二分查找)

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

在一门课程中,一共有n场考试。假如你在i场考试中可以答对bi道题中的ai道,那么你的累计平均分定义为:100·Σaibi。已知你这i场考试的答题情况,并且允许你放弃其中的k场考试,请你确定你最高能够得到多少的累计平均分。

假设该课程一共有3门考试,你的答题情况为5/5,0/1和2/6。如果你每门都参加,你的累计平均分为100·(5+0+2)/(5+1+6)= 50分。如果你放弃第3场考试,你的累计平均分则提高到了100·(5+0)/(5+1)= 83.33 ≈ 83分。

输入
有多组测试数据,每组测试数据包括3行。
每组测试数据第一行有两个数n和k,接下来一行有n个数ai,最后一行n个数bi。
(1 ≤ k < n ≤ 1000) (1 ≤ ai ≤ bi ≤ 1, 000, 000, 000)。
输入的最后一行为0 0,不作处理。
输出
输出最高的累计平均分。(四舍五入到整数)
样例输入
3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0
样例输出
83
100
来源
http://poj.org/problem?id=2976
最初的思路是把每一场的胜率排序,从高往底选择前n-k个,但是有正确率为零的场次要带入比较讨论,步骤就比较繁琐。
因此直接来个二分查找干。
#include <bits/stdc++.h>
using namespace std;

int a[1005],b[1005],n,k;
double ans,y[1005];
bool check(double v) {
    for(int i=0; i<n; i++) {
        y[i]=a[i]-v*b[i];            //理解的关键 
    }
    sort(y,y+n);
    double sum=0;
    for(int i=n-1; i>=k; i--) {
        sum+=y[i];
    }
    if(sum>=0)return true;
    else return false;
}
void fun(){
    double left=0,right=1;
    while(right-left>0.0001){
        double mid=left+(right-left)/2;
        if(check(mid))left=mid;
        else right=mid;
    }
    ans=left*100;
}
int main() {
    while(cin>>n>>k&&n!=0) {
        ans=0;
        for(int i=0; i<n; i++) {
            cin>>a[i];
        }
        for(int i=0; i<n; i++) {
            cin>>b[i];
        }
        fun();
        printf("%.0lf\n",ans);
    }

    return 0;
}

 

posted @ 2020-03-27 14:11  瓜瓜爱呱呱  阅读(828)  评论(1)    收藏  举报