【算法】最佳牛围栏(二分,前缀和,双指针)

题目 

农夫约翰的农场由 N 块田地组成,每块地里都有一定数量的牛,其数量不会少于 1 头,也不会超过 2000 头。

约翰希望用围栏将一部分连续的田地围起来,并使得围起来的区域内每块地包含的牛的数量的平均值达到最大。

围起区域内至少需要包含 F 块地,其中 F 会在输入中给出。

在给定条件下,计算围起区域内每块地包含的牛的数量的平均值可能的最大值是多少。

输入格式

第一行输入整数 N 和 F,数据间用空格隔开。

接下来 N 行,每行输入一个整数,第 i+1 行输入的整数代表第 i 片区域内包含的牛的数目。

输出格式

输出一个整数,表示平均值的最大值乘以 1000 再 向下取整 之后得到的结果。

数据范围

1 ≤ N ≤ 100000
1 ≤ F ≤ N

输入样例:

10 6
6 
4
2
10
3
8
5
9
4
1

输出样例:

6500

思路

       将每个农场的牛的数量存储到数组a[ ]中,二分平均值(答案),check()函数用来判断二分出来的平均值是否符合要求。

        其中s[ ]数组是s[i] = s[i - 1] + a[i] - avg;   得出来的 s[i]表示a[1]~a[ i ]中农场中牛的个数的平均值,由此可知,s[j] - s[i] 代表(i,j]的牛的数量的平均值。如下图所示:

【算法】最佳牛围栏(二分,前缀和,双指针)_第1张图片

check()数组代码: 

 【算法】最佳牛围栏(二分,前缀和,双指针)_第2张图片

代码 

#include
using namespace std;
const int N = 100010;
int n,f;
double a[N],s[N];

bool check(double avg)
{
    for(int i = 1; i <= n; i ++) s[i] = s[i - 1] + a[i] - avg;// 求出来前缀和
    double mins = 0;
    for(int k = f; k <= n; k ++)
    {
        mins = min(mins,s[k - f]);// 求出区间为f的农场牛的平均值的最小值
        if(s[k] - mins >= 0) return true;// 判断
    }
    return false;
}

int main()
{
    cin >> n >> f;
    double l = 0,r = 0;
    for(int i = 1; i <= n; i ++)
    {
        cin >> a[i];
        r = max(r,a[i]);
    }
      
    while(r - l > 1e-5)
    {
        double mid = (l + r) / 2;
        if(check(mid)) l = mid;
        else r = mid;
    }
    printf("%d",(int)(r * 1000));
    return 0;
}

题目来自: 102. 最佳牛围栏 - AcWing题库

难度:简单
时/空限制:1s / 64MB
总通过数:16264
总尝试数:39506
来源:《算法竞赛进阶指南》, POJ2018, kuangbin专题
算法标签:二分  icon-default.png?t=N7T8https://www.acwing.com/problem/search/1/?search_content=%E4%BA%8C%E5%88%86前缀和icon-default.png?t=N7T8https://www.acwing.com/problem/search/1/?search_content=%E5%89%8D%E7%BC%80%E5%92%8C   双指针icon-default.png?t=N7T8https://www.acwing.com/problem/search/1/?search_content=%E5%8F%8C%E6%8C%87%E9%92%88

你可能感兴趣的:(算法,算法,数据结构)