码迷,mamicode.com
首页 > 其他好文 > 详细

解题报告: AT1807

时间:2020-03-17 22:27:56      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:limits   赋值   stream   集合   函数   for   class   sort   个数   

题目链接:AT1807 食塩水
其实是很裸的二分最大化平均值,这里讲一下思路。
很容易发现\(check\)函数很难写,这就是因为找不到用单调性或是什么性质来判断,那我们构造一下不就得了?
假设我们对于一个数\(x\)进行\(check\),
我们设所选的\(k\)个数\(a_1\)\(a_k\)满足构成的集合为\(S\),那显然只需满足
\[\sum\limits_{i\in S}\dfrac{p_i}{w_i}\geqslant x\]
分数很别扭,乘过去,即得:
\[\sum\limits_{i\in S}p_i\geqslant \sum\limits_{i\in S}xw_i\]
移项,然后把求和合并起来:
\[\sum\limits_{i\in S}(p_i-xw_i)\geqslant 0\]
维护下每个\(p_i-xw_i\),从大到小排序贪心取前\(k\)大的即可(或后\(k\)小的)。

其他的事:
注意这里的\(p_i\)是浓度,我们要把它处理成溶质的质量;
另外,最后的答案是要\(×100\),因为我们是要用百分数表示答案的。
时间复杂度显然是\(O(n\log n\log eps)\)(这里的\(eps\)指的是精度,\(\log eps\)即二分次数,自己估算一下即可,反正\(100\)准是没问题的。)

\(Code\)

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm> 
#include<cstring>
using namespace std;
const int MAXN=1005;
const double EPS=1e-10;
int n,k;
double p[MAXN],w[MAXN];
double r=100.0,l=0.0,mid;
bool check(double x)
{
    double rt[MAXN],sum=0;
    memset(rt,0,sizeof(rt));//这里的清空是至关重要的,否则数组在函数中会任意赋值
    for(int i=1;i<=n;i++) rt[i]=p[i]-x*w[i];
    sort(rt+1,rt+n+1);
    for(int i=n;i>=n-k+1;i--) sum+=rt[i];//倒序就不用打cmp了
    return (sum-0)>EPS;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++) scanf("%lf%lf",&w[i],&p[i]),p[i]*=w[i]/100;
   //处理溶质的质量,另外记得用double读入
    for(int i=1;i<=100;i++)//二分
    {
        mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%.9lf\n",mid*100);//转化为百分数
    return 0;
}

解题报告: AT1807

标签:limits   赋值   stream   集合   函数   for   class   sort   个数   

原文地址:https://www.cnblogs.com/tlx-blog/p/12513967.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!