【问题描述】
农场主约翰的农场有一长排的 N 块地组成,每块地有一定数量的牛。约翰想修建环绕邻接的一组地块的栅栏,以最大化这组地块中平均每块地中牛的个数。这组地块必须包含至少 F 块地。 F 作为输入给出。
给定数据,请计算出栅栏的布置情况以最大化平均数。
【输入格式】
第一行: 空格分隔的两个整数, N 和 F。
第二到..N+1行: 每行包含一个整数,第i+1行的整数表示第i块地中的牛数。
【输出格式】
一个整数, 它是最大平均数的 1000 倍。不要用舍入求整, 仅仅输出整数。
【输入样例】
10 6
6
4
2
10
3
8
5
9
4
1
【输出样例】
6500
【数据范围】
1 <= N <= 100,000
每块地中牛的数量在1..2000之间。
题目的意思是给了你一个数列,要求数列中长度大于等于F的连续子序列的平均数尽量大。
二分(wunao)猜这个平均值m,然后带入m检验,看有没有一个长度大于等于F的连续子序列的平均值大于m,如果有就把m继续放大,直到不能找到这样的子序列使得它自身的平均数大于等于m为止,m就是答案。
但是代入检验原数列a[i]是否存在大于m的子序列太复杂,所以设c[i]=a[i]-m;只需求c[i]的最大连续子序列和,看是否大于等于0即可。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<queue>
#include<vector>
#define maxn 100005
#define eps 0.0000001
using namespace std;
int N,F,Min;
int a[maxn];
double sum[maxn];
double c[maxn];
bool check(double m)
{
memset(sum,0,sizeof(sum));
for(int i=1;i<=N;i++)
{
c[i]=a[i]-m;
sum[i]=sum[i-1]+c[i];
};
double Min=0,s;
for(int i=F;i<=N;i++)
{
s=sum[i]-Min;
if(s>=0)return 1;
Min=min(sum[i-F+1],Min);
}
return 0;
}
int main()
{
//freopen("my.in","r",stdin);
//freopen("my.out","w",stdout);
scanf("%d%d",&N,&F);
for(int i=1;i<=N;i++)
scanf("%d",&a[i]);
double A=0,B=2000,ans=0;
for(int i=1;i<=100;i++)
{
double mid=(A+B)/2;
if(check(mid))
A=mid+eps,ans=mid;
else
B=mid-eps;
}
printf("%.0lf\n",(ans*1000));
}