题目大意
% 给定 n n n 个物品,每个物品有两个参数, a i a_i ai 和 b i b_i bi,删除 k k k 个物品,最大化 z = 100 × ∑ a i ∑ b i . z=\cfrac{100\times{\sum} a_i}{{\sum}b_i}. z=∑bi100×∑ai.
% 数据范围 1 ⩽ k ⩽ n ⩽ 1000 1\leqslant k\leqslant n\leqslant 1000 1⩽k⩽n⩽1000, 1 ⩽ a i ⩽ b i ⩽ 1 0 9 1\leqslant a_i\leqslant b_i\leqslant 10^9 1⩽ai⩽bi⩽109
题解
%
对于一种可行的删除方案,有
100
×
∑
a
i
=
∑
b
i
×
z
.
100\times \sum a_i=\sum b_i\times z.
100×∑ai=∑bi×z.
%
移项,得
t
=
100
×
∑
a
i
−
∑
b
i
×
z
=
0.
t=100\times \sum a_i-\sum b_i\times z=0.
t=100×∑ai−∑bi×z=0.
%
对于某个
z
z
z,若存在一种删除方案,使得
t
>
0
t>0
t>0,则增大
z
z
z 后可以使得
t
=
0
t=0
t=0;若不存在一种删除方案,使得
t
⩾
0
t\geqslant0
t⩾0,则说明答案无法取到
z
.
z.
z.
综上所述,当
z
z
z 取最大值时,不存在一种删除方案,使得
t
>
0
t>0
t>0,且存在一种删除方案,使得
t
=
0
t=0
t=0。更进一步,当
z
z
z 取最大值,当且仅当
t
t
t 的最大值严格等于
0.
0.
0.
因此可以二分
z
z
z 的数值,每次求
t
t
t 的最大值,若
t
t
t 的最大值大于
0
0
0,则缩小
z
z
z,若
t
t
t 的最大值小于
0
0
0,则扩大
z
z
z,直到
t
t
t 的最大值严格等于
0.
0.
0.
#include<cstdio>
#include<cmath>
#include<functional>
#include<algorithm>
using namespace std;
#define maxn 1010
const double eps=1e-6;
int a[maxn],b[maxn],n,k;
double s[maxn];
double check(double z){
for(int i=1;i<=n;i++)//计算对t的贡献
s[i]=1.0*a[i]-b[i]*z;
sort(s+1,s+1+n);//按对t的贡献排序
double t=0;
for(int i=k+1;i<=n;i++)//丢掉前k个,取大的n-k个
t+=s[i];
return t;
}
int main(){
while(~scanf("%d%d",&n,&k)){
if(n==0&&k==0) break;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
scanf("%d",&b[i]);
double l=0,r=1;
while(r-l>=eps){//二分答案
double mid=(l+r)/2;
if(check(mid)>=0)l=mid;
else r=mid;
} printf("%.0f\n",r*100);
}
return 0;
}
% 本题的坑点:当且仅当 n n n 和 k k k 都为零时,表示程序解释, k k k 为0时继续运行。