题目传送门
分析
观察题目,会发现这是个区域减问题,问题在于如何选择策略使区域减的次数最少呢?
分块
每一块的大小是不均匀的,故而想要解决区间问题,最好的办法就是分块处理,可是该怎么分呢?
观察题目限制:
在最短的时间内将整段道路的下陷深度都变为 0
这个限制给了一个很好的启发:若 rk 为第 k 块的右边界,lk+1 为第 k+1 个块的左边界,满足 rk > lk+1 且第 k+1 块内的数值均满足 di ≥ di+1 ,则第k+1个块的贡献为 lk+1 - rk 。
如样例:
6
4 3 2 5 3 5
第二个块为 5 3 ,其贡献为 5-2=3 。
如何证明这个启发是对的呢?
假设我们是从左往右进行区间减,则为了保证每一个点的值变为 0 ,当某一点的值为 x 时,其右那个点的值可以免费地减去 [ 0,x ] ,故而可以轻松证明当第 k+1 块内的数值均满足 di ≥ di+1 时,其块内所有的值变为 0 的贡献等于把 lk+1 变为 0 的贡献,而第 k 个块的 rk 又会免费地减少 lk+1 的贡献,故而可证得上述启发是正确的。
这个启发是正确的关键点是每个值只能变为 0 ,而这个限制的本质作用就是隔绝了某一点除前一个点外前面所有点的影响,使该点的贡献为多少和是否作为新一个块的开始只取决于其前一个点,为分块提供了条件。
总结
说实话,本题不难,而上述观察就是我认为应该从本题学到的最关键的核心——影响的传递性和影响的被阻隔性
完整代码
#include<bits/stdc++.h>
using namespace std;
const int N=100005;
int n,a[N],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
ans=a[1];
for(int i=2;i<=n;i++){
int x=a[i];
if(a[i-1]<a[i]) x=max(0,x-a[i-1]),ans+=x;
}
cout<<ans<<endl;
return 0;
}