核心思路:逆向思维与差分思想
这道题表面上是一个复杂的“区间修改”问题,但如果我们转换视角,将其逆向思考,就会变得非常直观。 题目链接
1. 逆向思维:从“削减”到“堆叠”
题目要求将一排参差不齐的树全部减为 0,每次操作可以对一段连续的树高度减 1。由于减法和加法是完全可逆的,我们可以把这个问题等价转换为:
初始时所有树的高度都是 0,最少需要多少次“对一段连续的树高度加 1”的操作,才能恰好拼凑出题目给定的目标高度?
2. 直观想象:画山峰
想象我们在一张白纸上画一排柱子(山峰)。
- 当我们要画第一棵树(高度为 $a_0$)时,我们必须从它开始,连续发起 $a_0$ 次加 1 的操作。
当画到第二棵树(高度为 $a_1$)时,为了操作次数最少,我们会尽量让之前的操作“顺带”覆盖过来。
- 如果 $a_1 > a_0$,说明之前延续过来的操作不够用,我们必须额外发起 $a_1 - a_0$ 次仅从第二棵树开始的新操作。
- 如果 $a_1 \le a_0$,说明之前延续过来的操作已经足够覆盖当前树,甚至还会有多余的操作在这里自然“结束”,我们完全不需要增加新的操作次数。
3. 提炼规律
通过上述过程,我们可以得出一个普适的规律:只有当当前位置的树比前一棵树高时,我们才需要发起新的操作。
新发起的操作次数,恰好等于 当前高度 - 前一个高度。如果当前树比前一棵树矮或一样高,则不需要增加操作次数。
因此,整个问题的答案,就是遍历数组,累加所有“上升沿”的高度差。
完整代码
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
vector<long long> a(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
long long ans=0;
long long prev=0;
for(int i=0;i<n;i++){
if(a[i]>prev){
ans+=(a[i]-prev);
}
prev=a[i];
}
cout<<ans<<endl;
return 0;
}
评论 (0)