COW
COW:
题目描述:
Xiaoming's farm consists of a long row of N (1≤N≤100,000) fields. Each field contains a certain number of cows,0≤ncows≤2000. Xiaoming 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.
样例输入:
10 6
6
4
2
10
3
8
5
9
4
1
样例输出:
6500
题解:
题目大意:给出一个长度为n的数组,求其中长度不小于f的子序列的最大平均值。
这是一道二分题,这里二分答案即最大平均值,然后我们对于每一个二分值判断在序列中能否找到一段长度不小于f的子序列其平均值大于等于二分结果,如果存在则结果可以更大,所以取l=mid
,否则结果更小,所以取r=mid
。对于这题最难想的应该是如何判断区间是否存在一段长度不小于f的序列的平均值大于等于此时二分值。如果说对于一段区间其平均值大于等于mid,那么应该有区间和减去平均值乘以区间长度的结果大于等于0,即,\(\sum_{i=l}^r{sum[i]}-mid*(r-l+1)=\sum_{i=l}^r{(sum[i]-mid)}>=0\),由此想到用前缀和来处理,因为,我们只需找到区间最大的平均值满足条件即可,所以可以在O(n)下找到最大值,配合二分总的时间复杂度在O(log(2000)×n)。
/******************************************
/@Author: LeafBelief
/@Date: 2020-03-07
/@Remark:
/@FileName: cowsol
******************************************/
#include <bits/stdc++.h>
#define CSE(x, y) memset(x, y, sizeof(x))
#define lowbit(x) (x & (-x))
#define INF 0x3f3f3f3f
#define FAST \
ios::sync_with_stdio(false); \
cin.tie(0);
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int maxn = 111111;
int n, f;
double sum[maxn], arr[maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.in", "r", stdin);
#endif
FAST;
CSE(sum, 0);
CSE(arr, 0);
cin >> n >> f;
for (int i = 1; i <= n; i++)
{
cin >> arr[i];
}
double l = 0, r = 2002;
while (r - l > (1e-6))//扩大1000倍后保证数据准确性,所以进度开到了1e-6
{
double mid = (l + r) / 2.0;
double mn = INF;
double mx = -INF;
for (int i = 1; i <= n; i++)
{
sum[i] = sum[i - 1] + arr[i] - mid;//处理计算平均值的前缀和
}
//计算最大区间平均值
for (int i = f; i <= n; i++)
{
mn = min(mn, sum[i - f]);//维护从当前位置向前的最小左端点
mx = max(mx, sum[i] - mn);//用当前前缀和减去最小的左端点为当前的最大区间平均值,用mx不断取最大来维护结果
}
if (mx >= 0)//判断结果是否满足存在区间平均值大于等于当前结果
l = mid;
else
r = mid;
}
cout << int(r * 1000) << endl;
return 0;
}