2021-04-16-最佳牛围栏(二分+前缀和)

  1. 最佳牛围栏

https://www.acwing.com/problem/content/description/104/

步骤:

1、二分处理

2、前缀和处理

3、找最大的前缀和是否大于0

二分原理:因为所有平均值肯定介于0~2000之中,不可能大于最大值所以可以二分搜索出一个mid值判断是否是满足要求的平均值

(ai+ai+1+…aj )/i+j >= mid (j-i>-f)

移项并在在mid乘一个j+i 再除以一个j+i,可以视作把每个ai-aj的元素都减了一个mid值,然后判断是否大于0(这样就剩下了除以一个j+i的步骤不用考虑精度)

用前缀和更快的算出大于f范围内的和,用一个minv来记录0-i之间最小值,通过递增i来不断更新最小值,j初始化为f保证了j,i间距大于f(由于minv不一定是i位置的值,所以平均值的长度就肯定大于或者等于f)

注意:实数二分r=mid/l=mid即可且mid类型要开double

​ 由于题目要求乘1000所以精度一定是大于1e-3的,可以往1e-4或者1e-5开所以二分结束条件即为r-l>1e-4

#include<iostream>
#include<algorithm>
using namespace std;

int n,f;
const int N = 1000010;
int cows[N];
double sums[N];

bool calc(double ave)
{
    for(int i = 1;i<=n;i++)sums[i] = sums[i-1] + cows[i] - ave;
    double minv = 1000010;
    for(int i = 0,j = f;j<=n;i++,j++)
    {
        minv = min(minv,sums[i]);
        if(sums[j] >= minv)return true;
    }
    return false;
}
int main()
{
    cin>>n>>f;
    for(int i = 1;i<=n;i++)cin>>cows[i];
    double l = 0,r = 2000;
    while(r - l >1e-4)
    {
        double mid = (l+r)/ 2;
        if(calc(mid))
        l = mid;
        else 
        r = mid;
    }
    cout<<int(r*1000)<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值