AcWing 102. 最佳牛围栏—二分

3 篇文章 0 订阅
1 篇文章 0 订阅

题目链接: AcWing 102. 最佳牛围栏
问题描述
在这里插入图片描述
分析
这道题是一道比较巧妙的二分+前缀和问题,首先数据有1e5暴力枚举肯定行不通。
这里考虑二分方法,二分可能的avg,如果check(avg)=true这表示能够得到当前的avg,重点是如何判断当前的avg是可行的,二分的时间复杂度为O(logn),所以check的复杂度应该为O(n)的才行。

check函数只需要判断当前avg是否能取到就行,这里有一个巧妙地方法,我们让每个数减去avg,那么前缀和(>=f个数)的值大于0即可,如果不让每个数减去avg,那么我们需要算 h [ i ] − h [ j ] i − j > = a v g \frac{h[i]-h[j]}{i-j}>=avg ijh[i]h[j]>=avg,如果减去avg,我们只需要 h [ i ] − h [ j ] > = 0 h[i]-h[j]>=0 h[i]h[j]>=0就能说明当前avg可行。

考虑以某一个位置(>=f)为结尾位置的最大avg,也就是固定h[i],所以只需要求最小的h[j],j>=0,j<=i-f即可,因为最小的h[j]如果使得 h [ i ] − h [ j ] > = 0 h[i]-h[j]>=0 h[i]h[j]>=0就能说明当前avg可行,否则avg在以i位置为结尾不可行。因为i从小到达遍历,所以可以记录下所有j>=0,j<=i-f的最小值。

这道题还是挺精妙的,分析没看懂可以看代码,应该比较容易理解。

代码如下

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100010;

double f[N];
double h[N];
int n,k;

bool check(double avg){
    for(int i=1;i<=n;i++) h[i]=h[i-1]+f[i]-avg;
    double mins=0;
    for(int i=k;i<=n;i++){
        mins=min(mins,h[i-k]);
        if(h[i]-mins>=0) return true;
    }
    return false;
}
int main(){
    double l=0,r=0;
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        scanf("%lf",&f[i]);
        r=max(r,f[i]);
    } 
    while(r-l>=1e-5){
        double mid=(l+r)/2;
        if(check(mid)) l=mid;
        else r=mid;
    }
    printf("%d\n",int(r*1000));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值