Dropping tests(POJ-2976)(二分解法)

Problem 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

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

题意:多组数据,每组给出 n 个二元组 (a,b),扔掉 k 个二元组,使得剩下的 a 的和与 b 的和的比率最大

思路:

题目求的是:max(\sum\frac{a[i] * x[i]} { b[i] * x[i]}),其中 a[i]、b[i] 一一对应,x[i] 取 0、1,且 ∑x[i] = n - k

那么,令 r=\sum\frac{a[i]*x[i]}{b[i]*x[i]},则有:\sum a[i]*x[i]-\sum b[i]*x[i]*r=0

并有任意的:\sum a[i]*x[i]-\sum b[i]*x[i]*max(r)<=0

且当 \sum\frac{a[i]*x[i]}{b[i]*x[i]}=max(r) 时,\sum a[i]*x[i]-\sum b[i]*x[i]*max(r)=0成立

可以看出,上述的模型是一个标准的 01分数规划模型,因此,直接对每个物品重新赋值为 a-x*b,排序后直接取前 n-k 大,判断这个值的正负性,然后按上面的情况二分答案即可

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#define PI acos(-1.0)
#define INF 0x3f3f3f3f
#define LL long long
#define Pair pair<int,int>
LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; }
LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;}
LL quickMultPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;}
LL quickPowMod(LL a,LL b,LL mod){ LL res=1; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1; } return res; }
LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); }
LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); }
LL LCM(LL x,LL y){ return x/GCD(x,y)*y; }
const double EPS = 1E-7;
const int MOD = 1000000000+7;
const int N = 1000+5;
const int dx[] = {0,0,-1,1,1,-1,1,1};
const int dy[] = {1,-1,0,0,-1,1,-1,1};
using namespace std;

int n, k;
double a[N], b[N], c[N];
bool cmp(double x, double y) { 
    return x > y; 
}
bool judge(double x) {
    for (int i = 1; i <= n; i++)//重新赋值
        c[i] = a[i] - b[i] * x;

    sort(c + 1, c + n + 1, cmp);//从大到小排序

    double sum = 0;
    for (int i = 1; i <= n - k; i++)//计算前n-k个的和
        sum += c[i];
    if (sum > 0)
        return true;
    else
        return false;
}

int main() {
    while (scanf("%d%d", &n, &k) != EOF&&(n+k)) {
        for (int i = 1; i <= n; i++)
            scanf("%lf", &a[i]);
        for (int i = 1; i <= n; i++)
            scanf("%lf", &b[i]);

        double left = 0.0, right = 1.0;
        double res = 0;
        while (right - left >= EPS) {
            double mid = (left + right) / 2.0;
            if (judge(mid)) {
                left = mid;
                res = mid;
            } 
            else
                right = mid;
        }
        printf("%.0f\n", res * 100);
    }
    return 0;
}

 

posted @ 2022-09-20 22:50  老程序员111  阅读(15)  评论(0编辑  收藏  举报