【最大化平均值】 最佳牛围栏

传送门

题意

\(n\)个地,每个地都有一定数量的牛, 用围栏将一部分连续的地围起来,围起区域至少包含 \(f\) 块地,求围起来的牛数量平均值最大值,也就是求一个连续的子段使得这个子段的平均值最大

数据范围

\(1\leq n\leq 100000\)
\(1\leq f\leq n\)

题解

  • 二分平均值最大值,转化为判定子段和非负,利用前缀和可以快速求出子段和。

  • \(s_{i}=s_{i-1}+a_{i}−mid\),每个元素都要减去二分出的值,\(minv\)记录前缀和最小值,

  • 最大前缀和减去最小前缀和后才可能取到最大,然后判断是否大于等于\(0\)即可

  • 最后输出的时候要输出右边界,样例数据左边界可能会取到\(6.4999999\)而正确的答案是\(6.5\),取右边界

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n)for(int i=a;i<n;i++)
#define INF 0x3f3f3f3f
#define db double
#define eps 1e-7
#define ll long long
const int N=1e5+10;
int n,f;
db a[N],sum[N];
bool check(db mid)
{
    rep(i,1,n+1)
        sum[i]=a[i]-mid,sum[i]+=sum[i-1];
    db minv=INF;
    db res=-INF;
    rep(i,f,n+1)
    {
        minv=min(sum[i-f],minv);
        res=max(sum[i]-minv,res);
    }
    return res>=0?1:0;
}
int main()
{
    cin>>n>>f;
    rep(i,1,n+1)
        cin>>a[i];
    double l=0,r=INF;
    
    while((r-l)>eps)
    {
        db mid=(l+r)/2;
        
        if(check(mid))
            l=mid;
        else
            r=mid;
    }
    cout<<(ll)(r*1000)<<endl;
}
posted @ 2020-05-26 00:10  Hyx'  阅读(143)  评论(0编辑  收藏  举报