二分1 最佳牛围栏

在这里插入图片描述
题目大意:给我们一个序列,要求我们选择一段长度不小于f的连续区间,求合法区间中每个格子的最大平均值。
数据范围1e5,n2的算法无法完成。考虑二分答案,如何判断答案满不满足要求,即判断是否存在一个长度不小于f的连续区间,它的平均值大于等于二分出的答案。所以现在的问题转变成了如何写check函数。
如果我们不做任何处理,对于每个区间,我们既要求区间和,又要求区间长度,这很不好去维护。但是如果我们让所有数都减去一个平均值,我们只需要找一个长度不小于f的且区间和大于0的连续区间即可,我们只需要维护一个区间和就行了。假设b是原序列减去平均值后的序列,我们对他求前缀和s,枚举区间右端点i,在1~i-f+1中找一个左端点,使得s[i]-s[j-1]>=0。其实我们只需要在枚举右端点的过程中,依次更新1~i-f+1的最小值minn,判断s[i]-minn是否大于0。
代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5+10;
const double eps=1e-8;
double a[N],b[N],sum[N];
int n,f;
bool check(double x){
    double minn=0;
    for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i]-x;
    for(int i=f,j=0;i<=n;i++,j++){
        minn=min(minn,sum[j]);
        if(sum[i]-minn>=0)return true;
    }
    return false;
}
int main(){
    cin>>n>>f;
    for(int i=1;i<=n;i++)cin>>a[i];
    double l=0,r=2000;
    while(fabs(r-l)>eps){
        double mid=(l+r)/2;
        if(check(mid))l=mid;
        else r=mid;
    }
    printf("%d\n",(int)(r*1000));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值