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;
}	
posted @ 2020-03-07 10:55  落水清心  阅读(243)  评论(0编辑  收藏  举报