poj2018

  • Post author:
  • Post category:其他



题目描述


Description

Farmer John’s farm consists of a long row of N (1 <= N <= 100,000)fields. Each field contains a certain number of cows, 1 <= ncows <= 2000.

FJ wants to build a fence around a contiguous group of these fields in order to maximize the average number of cows per field within that block. The block must contain at least F (1 <= F <= N) fields, where F given as input.

Calculate the fence placement that maximizes the average, given the constraint.

Input

Line 1: Two space-separated integers, N and F.

Lines 2..N+1: Each line contains a single integer, the number of cows in a field. Line 2 gives the number of cows in field 1,line 3 gives the number in field 2, and so on.

Output

Line 1: A single integer that is 1000 times the maximal average.Do not perform rounding, just print the integer that is 1000*ncows/nfields.


Sample Input


10 6

6

4

2

10

3

8

5

9

4

1


Sample Output

6500

Source

USACO 2003 March Green

解题方法:

要求连续找到至少K个数 是的该区间内平均值最大。

一开始想的是遍历至少含有K个数字的区间 记录哪个平均值最大。我需要使用三重循环,这样是不现实的。

思路:利用二分思想,求其前缀和。

利用空间换区时间的做法,我先找到最中间的

定位点即 mid

;并记录与mid 差值的平均值

对区间进行计算,保存最大值的情况

接着对区间进行选取,一开始我看被人代码的时候,我不理解为什么要选取最小项。后来想到是公式:

a[n] = s[n+1]-s[n],所以当前面是最小的状态的时候后面的取的区间才会是最大的。

学习代码如下。

#include<iostream>
#include<cstring>
#include<algorithm>
#define maxn 3000
using namespace std;

int main(){
	int n,f;
	double l,s,mid;
	double a[200];
	double d[200];
	double sum[200]; 
	memset(a,0,sizeof(a));
	memset(d,0,sizeof(d));//记录平均数的差值; 
	memset(sum,0,sizeof(sum));
	l = 0; s = maxn;mid = 0 ;
	cin >> n >> f;
	for(int i = 1 ; i<= n ; ++i){
		cin >> a[i];
		l = max(l,a[i]);
		s = min(s,a[i]);
		//sum[i] = sum[i-1] + a[i];//计算前缀和 
	}
	
	while(l-s > 1e-4){
		mid = (l+s)/2;//是否为double?
		for(int i = 1 ; i <=n ;++i){
			d[i] = a[i] -mid;//计算差值 
		} 
		double max_sub_d = -1e9; double min_sub_d = 1e9;
		for(int i =1 ; i <= n ;++i){
			sum[i] = sum[i-1] +d[i];//与平均值的差值比较mid取得是否合适 
		}
		for(int i = f ; i <= n;++i){
			min_sub_d = min(min_sub_d,sum[i-f]); 
			max_sub_d = max(max_sub_d,sum[i]-min_sub_d);//算出最大k项至n中 最大的几项 
		} 
		if(max_sub_d >= 0) { //如果当前的平均值普遍偏大则扩大左极限范围 
			s = mid ;
		}
		else {//否则就缩小右极限 
			l = mid; //平均值是个基准数 
		}
		 
	}
	
	cout << int(l*1000) <<endl;
}

求其与平均数的差值,是在前缀和的基础上进行的改变。

当上下界限重合的时候就代表找到了。最终的这个位置就是所求得满足区间最大平均值的情况。、

涉及到的数学知识自己不是很有感觉。