题目描述
给定一个长度为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) {
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    } printf("%d\n", (int)(r * 1000));
    return 0; 
}