题目描述
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.
输入描述:

  • 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.
  • 输出描述*:
  • 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 。

题目简化
题目描述
给定一个长度为n的非负整数序列A,求一个平均数最大的,长度不小于L的子段 。

输入描述
第一行用空格分隔的两个整数n和L;
第二行为n个用空格隔开的非负整数,表示Ai。

输出描述:
输出一个整数,表示答案的1000倍。不用四舍五入,直接输出。

二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。

思路
可以先用二分查找到一个平均值avg来进行判定,能否成立一个子段大于等于F且大于等于这个平均值avg。
对于一段序列,每个数减去我们所算的平均数,如果大于0 那么他本身就大于平均数,如果小于0 那么它本身就小于平均数。
之后可以利用前缀和:s[i] = s[i - 1] + num[i] - avg。(关于这个式子怎么推出来的,我也表达不清楚(哭笑.jpg))如果这个前缀和中存在长度大于等于F且和大于等于0,就成立。

完整C++版AC代码

#include <cstdio>
#include <iostream>

const int N = 100005;
int cows[N]; double sum[N];

int n, m;

bool check(double avg) {
    for (int i = 1; i <= n; i++) {
        sum[i] = sum[i - 1] + cows[i] - avg;
    }

    double minv = 0;
    for (int i = 0, j = m; j <= n; j++, i++) {
        minv = std::min(minv, sum[i]);
        if(sum[j] - minv >= 0) return true;
    } return false;
}

int main() {
    scanf("%d %d", &n, &m);
    double l = 0, r = 0;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &cows[i]);
        r = std::max(r, (double)cows[i]);
    }

    while(r - l > 1e-5) {//以前这里我看成了r-1就导致了失误,结果是l。。。
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    } printf("%d\n", (int)(r * 1000));
    return 0; 
}