Dropping tests POJ 2976 二分

Dropping tests POJ 2976 二分

传送门:http://poj.org/problem?id=2976

Description
In a certain course, you take n n n tests. If you get a i a_i ai out of bi questions correct on test i i i, your cumulative average is defined to be
100 ∗ ∑ i = 1 n a i ‾ ∑ i = 1 n b i 100 *\begin{array}{c} \underline{\sum_{i=1}^na_i} \\{\sum_{i=1}^nb_i}\end{array} 100i=1naii=1nbi
Given your test scores and a positive integer k k 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 3 3 tests with scores of 5 / 5 5/5 5/5, 0 / 1 0/1 0/1, and 2 / 6 2/6 2/6. Without dropping any tests, your cumulative average is 100 ∗ 5 + 0 + 2 ‾ 5 + 1 + 6 = 50 100 *\begin{array}{c} \underline{5+0+2} \\5+1+6\end{array}=50 1005+0+25+1+6=50. However, if you drop the third test, your cumulative average becomes 100 ∗ 5 + 0 ‾ 5 + 1 ≈ 83.33 ≈ 83 100 *\begin{array}{c} \underline{5+0} \\5+1\end{array}≈83.33≈83 1005+05+183.3383.

Input
The input test file will contain multiple test cases, each containing exactly three lines. The first line contains two integers, 1 ≤ n ≤ 1000 1 ≤ n ≤ 1000 1n1000 and 0 ≤ k < n 0 ≤ k < n 0k<n. The second line contains n n n integers indicating a i a_i ai for all i i i. The third line contains n n n positive integers indicating b i b_i bi for all i i i. It is guaranteed that 0 ≤ a i ≤ b i ≤ 1 , 000 , 000 , 000 0 ≤ a_i ≤ b_i ≤ 1, 000, 000, 000 0aibi1,000,000,000. The end-of-file is marked by a test case with n = k = 0 n = k = 0 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 k k of the given test scores. The average should be rounded to the nearest integer.

Sample InputSample Output
3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0
1 2

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

题意:给出一个 n n n和一个 k k k n n n表示有 n n n a a a, b b b,每组 a a a, b b b相互配对,第 i i i组表示为 a [ i ] a[i] a[i] b [ i ] b[i] b[i] k k k表示我们需要在这 n n n a a a, b b b之间删除 k k k组。现问用最优的删除方式能够达到的 100 ∗ ∑ i = 1 n a i ‾ ∑ i = 1 n b i 100 *\begin{array}{c} \underline{\sum_{i=1}^na_i} \\{\sum_{i=1}^nb_i}\end{array} 100i=1naii=1nbi的最大值是多少。

思路:首先,我们假设x为小于等于最大答案的合法答案,则x应该满足,
x < = 100 ∗ ∑ i = 1 n a i ‾ ∑ i = 1 n b i = s ① x <= 100 *\begin{array}{c} \underline{\sum_{i=1}^na_i} \\{\sum_{i=1}^nb_i}\end{array}=s① x<=100i=1naii=1nbi=s

f ( x ) = ( x < = s ? 1 : 0 ) f(x)=(x<=s?1:0) f(x)=(x<=s?1:0)具有单调性,所以可以二分找答案。
即①式等于 x ∗ ( ∑ i = 1 n b i ) < = 100 ∗ ( ∑ i = 1 n a i ) {x*(\sum_{i=1}^nb_i )} <=100*({\sum_{i=1}^na_i}) xi=1nbi<=100(i=1nai)
⇨ 0 < = 100 ∗ ( ∑ i = 1 n a i ) − x ∗ ( ∑ i = 1 n b i ) ⇨ 0<=100*({\sum_{i=1}^na_i})-{x*(\sum_{i=1}^nb_i )} 0<=100(i=1nai)xi=1nbi
⇨ 0 < = ( ∑ i = 1 n a i ∗ 100 ) − ( ∑ i = 1 n b i ∗ x ) ⇨ 0<=({\sum_{i=1}^na_i*100})-{(\sum_{i=1}^nb_i*x )} 0<=(i=1nai100)i=1nbix
在check函数中,把所有的 a i ∗ 100 − b i ∗ x a_i*100-b_i*x ai100bix计算出来存在数组里,每次取最大的 n − k n-k nk个即可(相当于删去了最小的k个 a i ∗ 100 − b i ∗ x a_i*100-b_i*x ai100bix)。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std ;
#define ll long long
ll roundd(double number){return (number > 0.0) ? (number + 0.5) : (number - 0.5);}
const ll N = 5e3+9 ;
struct node{
    ll a , b , c ;
}sc[ N ];
bool cmp( double a , double b ){
    return a>b ;
}
ll n , k ;
bool check( double x ){
    double c[ N ] ;
    for( int i = 1 ; i <= n ; i ++ ) c[ i ] = 100*sc[ i ].a - x*sc[ i ].b ;
    sort( c+1 , c+1+n , cmp ) ;
    double sum = 0 ;
    for( int i = 1 ; i <= n-k ; i ++ ) sum += c[ i ] ;
    if( sum >= 0 ) return 1 ;
    else return 0 ;
}
int main(){
    while( scanf("%lld%lld",&n,&k) != EOF ){
        if( n == 0 && k == 0 ) break ;
        ll suma = 0 , sumb = 0 ;
        for( int i = 1 ; i <= n ; i ++ ) scanf("%lld",&sc[ i ].a) ;
        for( int i = 1 ; i <= n ; i ++ ) scanf("%lld",&sc[ i ].b) ;
        double l , r , mid , ans = 0.00 ;//注意ans无法更新时答案应该是0
        l = 0.00 , r = 1e17 ;
        for( int i = 0 ; i < 100 ; i ++ ){//10e-30
            mid = (l+r)/2.0 ;
            if( check( mid ) ){ l = mid ; ans = mid ; }
            else r = mid ;
        }
        printf("%lld\n",roundd(ans)) ;
    }
return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值