【算法竞赛进阶指南】最佳牛围栏 POJ 2018 Best Cow Fences (二分+贪心)

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

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

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

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

输入格式

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

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

输出格式

输出一个整数,表示围起区域内每块地包含的牛的数量的平均值可能的最大值乘以1000得到的数值。

数据范围

1≤N≤1000001≤N≤100000
1≤F≤N1≤F≤N

输入样例:

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

输出样例:

6500
难度:简单
时/空限制:1s / 64MB
总通过数:385
总尝试数:1180
来源:《算法竞赛进阶指南》

 

 

分析:

我们二分枚举mid为最后最大的平均值,单调性:不可能存在比ans更大的数,只能存在比ans更小的数。

对于check函数,我们首先对每一个数减去mid,计算前缀和,因为那么相当于寻找一个sum[j]-sum[i]>=0且j-i>m,则满足,继续寻求更大的,找不到寻求更小的。

对于判断一个sum[j]-sum[i]>=0且j-i>m,可以贪心的优化到O(n),

我们对于需要判断j来说,我们只需要找到一个i满足sum[j]-sum[i]>=0且j-i>m,即找到距离j大于大于m的最小的点即可。代码容易看懂。

n,m=input().split()
n=int(n)
m=int(m)
a=[0 for i in range(0,n+1)]
sum=[0 for i in range(0,n+1)]
for  i in range(1,n+1):
    a[i]=input()
    a[i]=int(a[i])


def check(mid):

    for i in range(1,n+1):
        sum[i]=sum[i-1]+a[i]-mid

    minv=1e10
    j=m
    for i in range(0,i+1):
        minv=min(sum[i],minv)
        if(j>n): break
        if(sum[j]>=minv): return 1
        j+=1

    return 0



eps=1e-6
l=0
l=0
r=2005
while(r-l>=eps):
    mid=(l+r)/2
    if(check(mid)==1):
        l=mid
    else:
        r=mid
print(int(r*1000))

 

你可能感兴趣的:(算法进阶指南好题,算法基础--二分,《算法进阶指南》好题)