• 最佳牛围栏题解 二分答案


    我真的会二分吗,显然是不,我还必须要学习

    对于这个题:https://www.acwing.com/problem/content/description/104/

    我们要找的是 有没有一段不小于F的区间,使这段区间的平均数尽可能的大,如果我们找到了一段连续的区间且区间长度不小于F且平均数大于我们二分的平均数

    那么大于这个数且区间也满足不小于F的一定满足 我们直接判断正确即可,这是证明其具有二分性;思考其具有单调性的原因;

    因为我们要找一段区间的平均数,根据平均数的小技巧,对于一段序列减去当前的avg,并且比较是否为0,大于0则大于平均数,使用前缀和,判断是否为正,

    判断存在平均值大于当前的avg,就能判断一个区间内的平均值是否大于或小于我们二分的平均数了

    我们还可以继续优化,因为我们不仅需要找F大小区间内,我们还要找>F大小区间内的,我们如果用二次枚举太费时间了,

    我们这里可以使用双指针的做法,我们设i=0,j=F 每次使两个数++ 因为i,j始终满足相距F的距离,但每次i增长,j只会+1,所以我们用一个变量minv来存储ii所遍历到的最小

    值,我们进行比较时,只需要将sum[j]与当前遍历到的最小值minv比较,这样我们比较的距离一定是≥F的,并且如果我们用j位的前缀和数减去minv的话,就能得到我们的最优解,如果这个最优解>= 0 那么就满足我们的指定条件。return true即可;

    二分答案要满足答案具有单调性,具有可二分性,而并不是这个序列的关系;

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N = 100010;
    
    int n, f;
    int a[N];
    double sum[N];
    double l = 0, r = 2000;
    
    template<typename T>inline void read(T &x)
    {
        x=0;T f=1,ch=getchar();
        while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
        while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
        x*=f;
    }
    
    bool check(double avg) {
        
        for (int i = 1; i <= n; ++i)
            sum[i] = sum[i - 1] + a[i] - avg;
        double minv = 0;
        for (int i = 0, j = f; j <= n; ++i, ++j) {
            minv =min(sum[i], minv);
            if (sum[j] - minv >= 0) return true;
        }
        return false;
    }
    
    
    int main() {
        read(n); read(f);
        for (int i = 1; i <= n; i++) 
            read(a[i]);
        
        double eps = 1e-5;
        while (r - l > eps) {
            double mid = (r + l) /2;
            if (check(mid)) l = mid;
            else r = mid;
        }
        cout << (int) (r * 1000);
    }
    View Code
  • 相关阅读:
    使用集合组织相关数据
    深入类的方法
    深入C#数据类型
    上机练习1 更新会员积分
    魔兽争霸登录
    jQuery
    打卡系统
    [工具]kalilinux2016.2 更新后
    [技术分享]借用UAC完成的提权思路分享
    [技术分享]利用MSBuild制作msf免杀的后门
  • 原文地址:https://www.cnblogs.com/Tyouchie/p/10863481.html
Copyright © 2020-2023  润新知