zoukankan      html  css  js  c++  java
  • 洛谷 P1570

    洛谷 P1570 - KC喝咖啡 - 二分答案

    二分答案简介

    二分答案是对于二分查找思想的一种应用。通过对答案出现的区间进行二分查找来判定可能的答案。二分答案一般用在以下情形的题目:

    • 直接求解答案十分复杂,或需要通过指数级别的枚举来完成。
    • 当以答案值ans作为函数自变量时,存在这样的一个单调函数可以作为区间折半的判定函数。

    一般而言,使用二分答案解题通常需要以下几步:

    1. 确定答案出现的区间范围
    2. 找到单调函数(最关键步骤)
    3. 二分答案,通过单调缩小答案区间。

    本题题解

    依题意,需要找到最大的答案(x),使得(x = frac{sum v_i}{sum c_i})。用搜索,复杂度为(2^n),01背包也行不通,本题的(x)表达式不满足dp的无后效性。而题目给出 (x in [0,1000]),考虑二分答案。注意本题(x)是小数形式,因此本题的大小判定需要针对浮点数重写比较函数或另外定义EPS。

    如何二分呢?注意到(x = frac{sum v_i}{sum c_i}),不妨设(y(x) = sum v_i - x * sum c_i = sum (v_i - x*c_i)) 。当进行二分的时候,正在判断(mid)的值是否为最大的(x),故需要检验 (y(mid)_{max})与0的大小关系

    • (y(mid)_{max} >= 0)

      这说明存在这样的一组方案使得(x = frac{sum v_i}{sum c_i} >= mid)。因此有(x in [mid,r])

    • (y(mid)_{max} < 0)

      这说明不存在这样的一组方案使得(x = frac{sum v_i}{sum c_i} >= mid),即所有的(frac{sum v_i}{sum c_i})都小于(mid)。因此有(x in [l,mid])

      另外,(y(mid)_{max})很好求,只需要分别计算(v_i - mid * c_i)后排序去后m个即可。

    答案

    #include <cstdio>
    #include <cmath>
    #include <vector>
    
    #define MaxN 200+5
    #define EPS 1e-6
    using namespace std;
    int v[MaxN]; // 美味度
    int c[MaxN]; // 时间
    
    bool bigthan(double a,double b){
        return a >= b + EPS;
    }
    
    bool equal(double a,double b){
        return fabs(a-b) < EPS;
    }
    double bs(int n,int m){
        double l = 0,r = 1000;
        while(bigthan(r,l)){
            double mid = (r + l) / 2;
            vector<double> vec;
            for(int i = 1; i <= n; i++){
                vec.push_back(v[i] - c[i]*mid);
            }
            sort(vec.begin(),vec.end());
            double sum = 0;
            for(int i = n-1; i >= n-m; i--){
                sum += vec[i];
            }
            if(bigthan(sum,0)){
                l = mid;
            }else{
                r = mid;
            }
        }
        return r;
    }
    int main(){
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i = 1; i <= n; i++){
            scanf("%d",&v[i]);
        }
        for(int i = 1; i <= n; i++){
            scanf("%d",&c[i]);
        }
        
        printf("%.3f",bs(n,m));
        return 0;
    }
    
    ---- suffer now and live the rest of your life as a champion ----
  • 相关阅读:
    DevExpress控件使用系列--ASPxUploadControl(图片上传及预览)
    DevExpress控件使用系列--ASPxGridView+Popup+Tab
    DevExpress控件使用系列--ASPxTreeList
    "Could not load type 'System.Runtime.CompilerServices.ExtensionAttribute' from assembly 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b7
    Asp.net实现直接在浏览器预览Word、Excel、PDF、Txt文件(附源码)
    ExtJs的事件机制Event(学员总结)
    Ext.Loader
    Ext.ComponentQuery.query()
    Ext.grid.Panel表格分页
    WPF概述
  • 原文地址:https://www.cnblogs.com/popodynasty/p/13658064.html
Copyright © 2011-2022 走看看