[poj P2976] Dropping tests

本文介绍了一种使用分数规划解决POJ P2976 Dropping Tests问题的方法,通过枚举和二分查找确定在丢弃k次测试成绩后能达到的最高累积平均分。

[poj P2976] Dropping tests

Time Limit: 1000MS  Memory Limit: 65536K

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

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).

Source

01分数规划入门题。

这个不等式会经常看到:sigma(ai)/sigma(bi)>=(或<=)k

对于这题来说就是,找出最大的k,使得100*sigma(ai)/sigma(bi)>=k。

我们尝试化简上式。

因为bi>=0,所以sigma(bi)>=0,100*sigma(ai)>=k*sigma(bi)

100*sigma(ai)-k*sigma(bi)>=0

sigma(100*ai-k*bi)>=0

那么,我们只要先枚举一个k,将100*ai-k*bi作为关键字排序,再选出前n-k大的,判断一下sum是否非负就行了。

然后我们发现,上式满足单调性,枚举可以改为用二分。所以总复杂度是O(nlog分数)。

然后这一题我先开大100倍,然后最后再缩小100倍,但是这也会有精度误差。

总之,开大的倍数越大,误差越小,但效率越低,但也低不到哪里去qwq

code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define LL long long
 5 #define M ((L)+(R)>>1)
 6 using namespace std;
 7 const int N=1005,lim=10000;
 8 int n,k,L,R,ans,final; LL sum;
 9 struct ob {LL a,b,c;}o[N];
10 bool cmp(ob x,ob y) {return x.c>y.c;}
11 bool jug(LL lv) {
12     for (int i=1; i<=n; i++) o[i].c=o[i].a*lim-lv*o[i].b;
13     sort(o+1,o+1+n,cmp);
14     sum=0;
15     for (int i=1; i<=n-k; i++) sum+=o[i].c;
16     return sum>=0;
17 }
18 int main() {
19     while (scanf("%d%d",&n,&k)!=EOF,n|k) {
20         for (int i=1; i<=n; i++) scanf("%lld",&o[i].a);
21         for (int i=1; i<=n; i++) scanf("%lld",&o[i].b);
22         for (L=0,R=lim; L<=R; )
23             if (jug(M)) ans=M,L=M+1;
24             else R=M-1;
25         final=ans/100; ans%=100;
26         if (ans>=50) final+=1;
27         printf("%d\n",final);
28     }
29     return 0;
30 }
View Code

转载于:https://www.cnblogs.com/whc200305/p/7750209.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值