zoukankan      html  css  js  c++  java
  • 解题报告: AT1807

    题目链接:AT1807 食塩水
    其实是很裸的二分最大化平均值,这里讲一下思路。
    很容易发现(check)函数很难写,这就是因为找不到用单调性或是什么性质来判断,那我们构造一下不就得了?
    假设我们对于一个数(x)进行(check),
    我们设所选的(k)个溶液构成的集合为(S),那显然只需满足

    [dfrac{sumlimits_{iin S}p_i}{sumlimits_{iin S}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;
    }
    
  • 相关阅读:
    证明 O(n/1+n/2+…+n/n)=O(nlogn)
    ZOJ 3623 Battle Ships DP
    ZOJ 3631 Watashi's BG DFS
    ZOJ 3622 Magic Number 打表找规律
    poj 1088 滑雪 记忆化搜索
    poj 1273 Drainage Ditches 网络流最大流基础
    Codeforces Round #243 (Div. 1)A. Sereja and Swaps 暴力
    UVALive 5059 C
    Codeforces Round #295 (Div. 2)C
    Codeforces Round #295 (Div. 2)B
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12513967.html
Copyright © 2011-2022 走看看