H-钟别 牛客小x白月赛 遍历决策点,前缀和巧妙处理O(1)

题意

给出一个序列,每次操作都能使得相邻的三个数字减1,并且有一次机会,能直接让两个相邻的数字变为0,现在求最多要多少次操作才能让数字都<=0

解析

  • List item
  • 假设不动用机会,我们如何把所有数字变为<=0 ,对于最左边的数字假设是a[1],那么我们一定要花费a[1]次操作,将a[1]处理完,对于数字a[2]已经是边界,因此我们必须要花费a[2]-a[1]的操作,但是我们不知道a[2]-a[1]是否大于0,那么就要max(0,a[2]-a[1]),因此我们可以按这样最优的贪心下来算出最终结果。
  • 由于只需要<=0即可,所以我们使用机会让两个数字为0不确定放在哪,那么我们是否可以遍历机会使用的位置,并且通过O(1)的时间得到结果呢?
  • 答案是,前缀和。
  • 首先我们不用机会,朴素的算下来,得到每个从前到后,从后到前的前缀,如果我们对a[i],a[i+1]使用机会,那么左边和右边就互不影响,我们用刚刚算的前缀即可O(1)时间得到结果。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
ll a[N],b[N],L[N],R[N];
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        b[i]=a[i];
    }
    for(int i=1;i<=n;i++){
        L[i]=L[i-1]+a[i];
        a[i+1]=max(0ll,a[i+1]-a[i]);
        a[i+2]=max(0ll,a[i+2]-a[i]);
    }
    for(int i=n;i>=1;i--){
        R[i]=R[i+1]+b[i];
        if(i>=2){
            b[i-1]=max(0ll,b[i-1]-b[i]);
            b[i-2]=max(0ll,b[i-2]-b[i]);
        }
    }
    ll res=1e18;
    for(int i=1;i<=n;i++){
        res=min(res,L[i-1]+R[i+2]);
    }
    printf("%lld",res);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值