题目描述
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; }