每日一题——Best Cow Fences

题目

Best Cow Fences

引言

对于二分,我们先引入模板。二分模板一共有两个,分别适用于不同情况,mid在哪一边,版本1属于左半边,版本2属于右半边。
算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。

版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

版本2
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

对于实数二分,精度由eps决定,若需要保持k位,eps位1e(-k-2),比如保留四位eps=1e-6。

int bsearch_3(int l, int r)
{
    double eps = 1e-6;
    while (r - l > eps)
    {
        double mid = l + r >> 1;
        if (check(mid)) l = mid;
        else r = mid;
    }
    return l;
}

题解

回归正题,二分的使用不一定在于单调性,而在于他是否能将一个区间分成两半,一半满足,一半不满足。那么我们判断是否存在一个平均值大于等于mid,如果最优解是x,那么mid <= x的时候,必然可以找到一段,其平均值≥mid,否则一定找不到。我们可以将每个数减去平均数mid,若大于0说明它本身大于平均数,若小于0说明他本身小于平均数,然后对于一个区间和来说大于0,就是说明它的平均数比mid大。而区间和可以用前缀和的思想来实现,即sum[i]-sum[j]>0就是存在一个区间[j+1,i]满足平均数大于mid,而这里的j是可以从1枚举到i-m+1的,取他们中间最小的就行了。

参考代码

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
int n, m;
int cow[N];
double sum[N];
bool check(double avg){
    for(int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + cow[i] - avg;
    double minv = 0;
    for(int i = m, j = 0; i <= n; i ++, j ++){
        minv = min(minv, sum[j]);
        if(sum[i] >= minv) return true;
    }
    return false;
}
int main(){
    cin >> n >> m;
    for(int i = 1; i <= n; i ++) cin >> cow[i];
    double l = 0, r = 2000;
    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;
}
posted @ 2025-03-12 21:24  PZnwbh  阅读(21)  评论(0)    收藏  举报