【最大化平均值】 最佳牛围栏
传送门
题意
\(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;
}