POJ 2018 Best Cow Fences【二分答案+最大子段和+前缀和】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37867156/article/details/81877612

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

题目描述:给定一个正整数数列A,求一个平均数最大的、长度不小于L的子段。

分析:二分答案,判定是否存在一个长度不小于L的子段,平均数不小于二分的值。如果把数列中的每个数都减去二分的值,就转换为判定“是否存在一个长度不小于L的子段,子段和非负”。

      求一个子段,它的和最大,子段的长度不小于L。

子段和可以转换为前缀和相减的形式,即设sumj表示Ai~Aj的和,

则有:max{A[j+1]+A[j+2].......A[i] } ( i-j>=L ) = max{ sum[i] - min{ sum[j] }(0<=j<=i-L) }(L<=i<=n)

仔细观察上面的式子可以发现,随着i的增长,j的取值范围 0~i-L 每次只会增大1。换言之,每次只会有一个新的取值进入 min{sumj} 的候选集合,所以我们没必要每次循环枚举j,只需要用一个变量记录当前的最小值,每次与新的取值 sum[i-L] 取min 就可以了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int maxn=100005;
double a[maxn],b[maxn],sum[maxn];
int main(){
	int N,F;
	scanf("%d %d",&N, &F);
	for(int i=1; i <= N; i++)
		scanf("%lf", &a[i]);
	double eps=1e-5;
	double l=-1e6, r=1e6;
	while(r - l > eps) {
		double mid = (l + r) / 2;
		for(int i=1; i <= N; i++)
			b[i] = a[i] - mid;
		for(int i = 1; i <= N; i++)
			sum[i] = sum[i-1] + b[i];
		double ans = -1e10;
		double min_val = 1e10;
		for(int i = F; i <= N; i++){
			min_val = min(min_val, sum[i-F]);
			ans = max(ans, sum[i]-min_val);
		}
		if(ans >= 0) l = mid;
		else r = mid;
	}
	printf("%d\n",int(r*1000));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37867156/article/details/81877612