[NOIP2018 提高组] 铺设道路

题目传送门

洛谷P5019

分析

观察题目,会发现这是个区域减问题,问题在于如何选择策略使区域减的次数最少呢?

分块

每一块的大小是不均匀的,故而想要解决区间问题,最好的办法就是分块处理,可是该怎么分呢?

观察题目限制:

在最短的时间内将整段道路的下陷深度都变为 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值