积木大赛

题目链接
在这里插入图片描述
输入样例:

5
2 3 4 1 2

输出样例:

5

分析: y总写的太好,直接转发了
算法
(差分,贪心) O ( n ) O(n) O(n)
我们逆向思考:假设给定了每块积木的高度,每次可以将某一段区间中的所有高度减一,问最少操作多少次可以将所有高度变成0。

原序列是: h 1 , h 2 , h 3 , … , h n , 其 中 h i ≥ 1 h_1,h_2,h_3,…,h_n, 其中 h_i≥1 h1,h2,h3,,hn,hi1

构造差分序列:

b 1 = h 1 b_1=h_1 b1=h1
b 2 = h 2 − h 1 b_2=h_2−h_1 b2=h2h1
b 3 = h 3 − h 2 b_3=h_3−h_2 b3=h3h2
… …
b n = h n − h n − 1 b_n=h_n−h_{n−1} bn=hnhn1
b n + 1 = − h n b_{n+1}=−h_n bn+1=hn
则将 h L , h L + 1 , … , h R h_L,h_{L+1},…,h_R hL,hL+1,,hR中的每个数减1的操作,等价于将 b_L 减1, 将 b R + 1 b_{R+1} bR+1 加1。

因此问题变成每次从 b 1 , b 2 , … , b n b_1,b_2,…,b_n b1,b2,,bn 中挑两个数,前一个减1,后一个加1,问最少操作多少次可以将所有数变成0。

首先,对于每个正数 b i > 0 b_i>0 bi>0,最少需要操作 b i b_i bi 次,因此总操作次数一定不少于差分数组中所有正数之和 B。

然后我们构造一种操作方式,使得恰好可以通过 B 次操作,将所有数变成0。 那么就可以说明最少操作次数一定是所有正数之和。

操作方式如下:

从后往前操作,如果当前的 b i > 0 bi>0 bi>0,则将其减1,并将其后的某个负数加1。
由于 ∑ b i = 0 ∑b_i=0 bi=0,因此从数量上看,正数和负数是一一对应的。
然后我们考虑在操作过程中,对于每个正数 bibi,其后是否一定存在负数与之对应。由于差分数组的所有后缀 ∑ i = k n = 1 b i = − b k < = 0 \sum_{i=k}^{n=1}b_i=-b_k<=0 i=kn=1bi=bk<=0,因此在所有后缀中,正数之和一定小于等于负数之和,所以负数总是可以被找到的。
因此,上面的操作方式是合法的。
时间复杂度
求差分序列扫描一遍数组即可,因此总时间复杂度是 O ( n ) O(n) O(n)
参考作者:yxc
链接:https://www.acwing.com/solution/content/3256/
代码如下

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
const int N=1e5+10;
int n,q[N],b[N],res=0;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>q[i];
    for(int i=1;i<=n;i++ ) 
    {
        b[i]+=q[i];
        b[i+1]-=q[i];
        res+=max(0,b[i]);
    }
    cout<<res<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值