题意
有 (n) 瓶食盐水,第 (i) 瓶为质量 (w_i),浓度 (p_i\%) 的食盐水,需要选出 (k) 瓶食盐水混合在一起,问最大浓度。
( exttt{Data Range:}1leq n,kleq 1000)
题解
二分答案。
一开始在想各种贪心,然后各种贪心都假了,但是注意到这个东西是有单调性,(如果存在一种方案混合出来的食盐水浓度大于 (p) 那么也一定存在一种方案的浓度大于比 (p) 小的值),所以可以二分答案变成判定性问题。
现在考虑能不能选出 (k) 瓶食盐水混合起来浓度大于某个二分到的 (p),也即:
[frac{sumlimits_{i=1}^{k}w_ip_i}{sumlimits_{i=1}^{k}w_i}geq p
]
乘过去再移过来
[sumlimits_{i=1}^{k}w_i(p_i-p)geq 0
]
所以说我们只需要对 (w_i(p_i-p)) 排序然后贪心选最大的 (k) 个即可,实现可能有一些细节需要注意。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
typedef long double db;
const ll MAXN=2e5+51;
const db eps=1e-10;
struct Node{
ll p,w;
};
Node x[MAXN];
ll n,kk;
db l,r,mid;
db c[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline ll check(db mid)
{
db c2=0;
for(register int i=1;i<=n;i++)
{
c[i]=(x[i].p-mid)*x[i].w;
}
sort(c+1,c+n+1,greater<db>());
for(register int i=1;i<=kk;i++)
{
c2+=c[i];
}
return c2>=0;
}
int main()
{
n=read(),kk=read(),l=0,r=100;
for(register int i=1;i<=n;i++)
{
x[i].w=read(),x[i].p=read();
}
while(r-l>=eps)
{
mid=(l+r)/2;
check(mid)?l=mid:r=mid;
}
printf("%.9Lf
",l);
}