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 0Sample Output
83
100
题意:多组数据,每组给出 n 个二元组 (a,b),扔掉 k 个二元组,使得剩下的 a 的和与 b 的和的比率最大
思路:
题目求的是:,其中 a[i]、b[i] 一一对应,x[i] 取 0、1,且 ∑x[i] = n - k
那么,令 ,则有:
并有任意的:
且当 时,
成立
可以看出,上述的模型是一个标准的 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;
}