Dropping tests POJ 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}
100∗∑i=1nai∑i=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 100∗5+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 100∗5+05+1≈83.33≈83.
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
1≤n≤1000 and
0
≤
k
<
n
0 ≤ k < n
0≤k<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
0≤ai≤bi≤1,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 Input | Sample 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} 100∗∑i=1nai∑i=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<=100∗∑i=1nai∑i=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})
x∗(i=1∑nbi)<=100∗(i=1∑nai)
⇨
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=1∑nai)−x∗(i=1∑nbi)
⇨
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=1∑nai∗100)−(i=1∑nbi∗x)
在check函数中,把所有的
a
i
∗
100
−
b
i
∗
x
a_i*100-b_i*x
ai∗100−bi∗x计算出来存在数组里,每次取最大的
n
−
k
n-k
n−k个即可(相当于删去了最小的k个
a
i
∗
100
−
b
i
∗
x
a_i*100-b_i*x
ai∗100−bi∗x)。
代码:
#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 ;
}