Best Cow Fences
poj 2018
题目大意:
给出一个正整数数列,要你求平均数最大,长度不小于M的字串,结果乘1000取整
输入样例
10 6
6
4
2
10
3
8
5
9
4
1
输出样例
6500
数据范围
1⩽N⩽100,0001\leqslant N \leqslant 100,0001⩽N⩽100,000
解题思路:
我们先想一想,如何求一个长度不小于M且和最大的字段,我们可以设两个值num和minn分别表示结果和前面减去的最小值
我们图文结合(如下图,当n为5,M为2)
我们先枚举i(从m到n),表示当前字段的结尾位置,因为长度不能小于M,所以红色部分是必须选的,然后前面的黄色部分是可选可不选的,我们到每一个位置时就更新一遍,就相当于求一个和最小的字段,然后到时直接用sum[i](前缀和)减去它,就可以更新num了
因为他求的是平均值最大的,所以我们每次把所有数减去我们二分得到的结果,然后看一看所得的num是否是非负数,如果是就说明可以找到这样的一个字段,否则没有
代码:
#include<cstdio>
#define min(a,b) (a)<(b)?(a):(b)
#define max(a,b) (a)>(b)?(a):(b)
using namespace std;
int n,m;
double l,r,mid,num,minn,a[100500],sum[100500];
int main()
{scanf("%d %d",&n,&m);for(int i=1;i<=n;++i)scanf("%lf",&a[i]);l=-1e6;r=1e6;while(r-l>1e-5){mid=(l+r)/2;//二分for (int i=1;i<=n;++i)sum[i]=sum[i-1]+a[i]-mid;//求前缀和num=-1e10;minn=1e10;for(int i=m;i<=n;++i){minn=min(minn,sum[i-m]);//计算减去的最小是多少num=max(num,sum[i]-minn);//计算结果}if(num>=0) l=mid;//判断是否存在else r=mid;}printf("%d",(int)(r*1000));
}