题目大意:
小明的农场由一长排N块(1≤N≤100,000)田地组成。每块田都有一定数量的奶牛,0≤奶牛≤2000。
小明想在这些田地的连续组周围建一个围栏,以使该区块内每块田地的平均奶牛数量最大化。该区块必须至少包含F(1≤F≤N)块田地,其中F为输入值。
在给定的约束条件下,计算出使平均数最大化的围栏位置。
输入格式
*第1行。两个隔开空间的整数,N和F。
* 第2...N+1行:每行包含一个整数,即田地里的奶牛数量。第2行给出田间1的奶牛数,第3行给出田间2的奶牛数,以此类推。
输出格式
* 第1行。一个单一的整数,是最大平均数的1000倍。不要进行四舍五入,只需打印(1000×奶牛)/田地的整数。
解题思路:
如果去二分一个块,没有规律。所以去想到二分答案,又是平均数所以采用浮点数二分。
问题关键:
二分的 check() 函数如何去写?二分到的mid是假设的答案,让每一个数减去mid
问题转化为:是否存在一个连续的区间,区间和大于0且区间长大于等于F.
查询一个区间和 可以用前缀和的思路 以sum[N] 为例。
问题再转化为: 是否存在 sum[j]-sum[i-1]>0&&j-i+1>=F (j>=F&&j<=n)
sum[i-1] 要越小越好 枚举每一个符合条件的i,更新最小值。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int a[N];
double sum[N];
int n,f;
int check(double mid){
for(int i=1;i<=n;i++){
sum[i]=sum[i-1]+a[i]-mid;
}
double midx=N;
for(int i=0,j=f;j<=n;i++,j++){
midx=min(midx,sum[i]);
if(sum[j]-midx>0) return 1;
}
return 0;
}
int main(){
scanf("%d%d",&n,&f);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
double l=0,r=3e3;
while(r-l>=1e-5){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
cout<<int(r*1000);
return 0;
}