zoukankan      html  css  js  c++  java
  • 102. 最佳牛围栏(二分)

    102. 最佳牛围栏

    https://www.acwing.com/problem/content/104/
    农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头。

    约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。

    围起区域内至少需要包含 F 块地,其中 F 会在输入中给出。

    在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。

    输入格式

    第一行输入整数 NF ,数据间用空格隔开。

    接下来N 行,每行输出一个整数,第i+1行输出的整数代表,第i片区域内包含的牛的数目。

    输出格式

    输出一个整数,表示平均值的最大值乘以1000再向下取整之后得到的结果。

    数据范围

    1≤N≤100000
    1≤F≤N

    输入样例

    10 6
    6 
    4
    2
    10
    3
    8
    5
    9
    4
    1
    

    输出样例

    6500
    

    当我知道这道题是用二分来做的时候,我觉得很迷幻,不科学,给的数据不是单调的,又不能排序,分个锤子,看了题解以后,才发现自己对二分的理解过于肤浅。
    这个问题可以这样想,假设存在一个答案ans,对于任意的数avg,check(avg)一定可以判断它符不符合条件,再利用二分,不断让avg逼近ans,最后check出来的a就是答案。

    关键的check代码

    bool check(double avg)
    {
        for(int i=1;i<=n;i++)
            sum[i]=sum[i-1]+a[i]-avg;//简单的数学知识,求前缀
        double minn=0;
        for(int i=0,j=m;j<=n;j++,i++)
        {
            minn=min(minn,sum[i]);//利用俩个指针i,j,来维护满足条件的连续子序列
            if(sum[j]-minn>0)return true;//对于这个avg只要在数列中找到一个满足的就行了
        }
        return false;
    }
    

    完整代码

    #include <bits/stdc++.h>
    #define love ios::sync_with_stdio(false);
    #define inf 0x7fffffff
    #define INF 0x7fffffffffffffff
    typedef long long ll;
    const double PI=3.1415926535897931;
    //const long long mod=1e9+7;
    using namespace std;
    //////////////////////////////////////////////
    const int N=1e5+10;
    double a[N];
    double sum[N];
    double n,m;
    bool check(double avg)
    {
        for(int i=1;i<=n;i++)
            sum[i]=sum[i-1]+a[i]-avg;
        double minn=0;
        for(int i=0,j=m;j<=n;j++,i++)
        {
            minn=min(minn,sum[i]);
            if(sum[j]-minn>0)return true;
        }
        return false;
    }
    int main()
    {
        //freopen("int.txt","r",stdin);
        //freopen("out.txt","w",stdout);
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            cin>>a[i];
        double r=2010,l=0;
        while(r-l>1e-5)
        {
            double mid=(l+r)/2;
            if(check(mid))
                l=mid;
            else
                r=mid;
        }
        cout<<(int)(r*1000)<<endl;
        return 0;
    }
    
  • 相关阅读:
    【Visual C++】游戏开发笔记之六——游戏画面绘图(三)透明特效的制作方法
    【不定期更新】游戏开发中的一些良好习惯与技术技巧
    【Visual C++】游戏开发笔记之七——基础动画显示(一)定时器的使用
    【超级经典】程序员装B指南(转)
    Gentoo安装小记
    图形学中的贴图采样、走样与反走样等
    面试题之银行业务调度系统
    四川雅安芦山加油挺住
    ZOJ 3223 Journey to the Center of the Earth
    android中ListView拖动时背景黑色的问题
  • 原文地址:https://www.cnblogs.com/Aracne/p/12851933.html
Copyright © 2011-2022 走看看