L : [算法竞赛进阶指南]最佳牛围栏
Time Limit:2 Sec Memory Limit:128 MiB
Back Submit Edit
Description
【poj2018】农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于1头,也不会超过2000头。
约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。
围起区域内至少需要包含 F 块地,其中 F 会在输入中给出。在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。
题意 : 给定正整数数列A,求一个平均数最大的、长度不小于F的(连续的)字段
Input
第一行输入整数 N 和 F ,数据间用空格隔开。1 ≤ F ≤ N ≤ 100000
接下来 N 行,每行输出一个整数,第i+1行输出的整数代表,第i片区域内包含的牛的数目。
Output
输出一个整数,表示围起区域内每块地包含的牛的数量的平均值可能的最大值乘以1000得到的数值。
Sample Input
10 6
6
4
2
10
3
8
5
9
4
1
Sample Output
6500
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100010;
int n,f;
//该题利用实数域的二分的方法
int cows[maxn];//定义每块地牛的数量
double sum[maxn];//存放用于求平均值的数组,(利用子段和序列)
bool check(double avgs)
{
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+cows[i]-avgs;//cows[i]-avgs相当于将每个围栏的牛的数目都减去平均值
//sum[i]=sum[i-1]+cows[i]-avgs; 是求它们的子段和这样的话只要存在某一段它们的子段和大于等于0就相当于
//cows数组中有一段子段和大于等于avgs
double minl=9999;
for(int i=0,j=f;j<=n;i++,j++)
{minl=min(minl,sum[i]);
//minl存储的是j子段以前和最小的值
//并且由于minl指代的值小于等于i的位置那么当前与其之间的距离一定大于等于f
if(sum[j]-minl>=0)return true;//符合平均数判断的条件
}
return false;
}
int main(){
//freopen("qwe.txt","r",stdin);
cin>>n>>f;
for(int i=1;i<=n;i++)
cin>>cows[i];
double l=0,r=2000;//实数域二分端点最大平均数是2000,左端点要从0开始
while(r-l>1e-5)
{
//实数域二分模板
double mid=(r+l)/2; //注意二分模板是左右端点相加不要错误写成相乘
if(check(mid))l=mid;
else r=mid;
}
cout<<int(r*1000)<<endl;
return 0;
}