解题报告: AT1807

Posted tlx-blog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解题报告: AT1807相关的知识,希望对你有一定的参考价值。

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

其他的事:
注意这里的(p_i)是浓度,我们要把它处理成溶质的质量;
另外,最后的答案是要(×100),因为我们是要用百分数表示答案的。
时间复杂度显然是(O(nlog nlog 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
",mid*100);//转化为百分数
    return 0;
}

以上是关于解题报告: AT1807的主要内容,如果未能解决你的问题,请参考以下文章

AT1219 歴史の研究 解题报告

LeetCode --- 1450. Number of Students Doing Homework at a Given Time 解题报告

LeetCode --- 1450. Number of Students Doing Homework at a Given Time 解题报告

LeetCode --- 1437. Check If All 1‘s Are at Least Length K Places Away 解题报告

LeetCode --- 1437. Check If All 1‘s Are at Least Length K Places Away 解题报告

解题报告: ABC 165C