CodeForces-1407-D

题目名称:

Discrete Centrifugal Jumps

题目大意:

有n个楼房,给出n个楼房的高度,开始位于1号楼,最后需到达n号楼。当满足一下任一条件则可转移:

i + 1 = j;

max(hi+1,…,hj-1)<min(hi,hj);

max(hi,hj)<min(hi+1,…,hj-1);

求到达n号楼需要的最少步数。

思路:

根据条件有如下转移:

1.dp[i]=dp[i-1]+1;

2.i前面有一个下标假设为j,且这个j满足(a[j]>max(a[j+1]…,a[i-1]); dp[i]=dp[j]+1;

3.i前面有一个下标假设为j,且这个j满足(a[j]<min(a[j+1]…a[i-1]);dp[i]=dp[j]+1;

那么找这个j的过程用单调栈优化。

具体是什么意思呢?

比如现在有

h[i]:4 3 2 5 这样的楼高度

i : 1 2 3 4

设一个down的单调栈,维护栈内的元素是单调递减的。当遍历到i=4的时候,由于h[4]>h[down.top() =(3) ] ,那么此时down栈的单调递减性质破坏,需要不停down.pop(),使得栈里没有比h[4]更校的。让这个h[4]来当down栈此时的龙头。

于是在pop()的过程中,最开始的down.top=3,但是这个是和i=4相邻的,在转移最开始我们就进行了dp[i]=dp[i-1]+1;所以这里其实无所谓第一个top的转移。但是当第二个down.top()==2的时候,这时候进行dp[i]=min(dp[i],dp[down.top]+1)的转移。如此往复到i=n的时候就维护好了。优化了不停找j的过程。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+50;
int h[maxn],dp[maxn],n,d[maxn],top1,u[maxn],top2;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>h[i];
		dp[i]=i;
	}
	dp[1]=0;
	d[++top1]=1,u[++top2]=1;
	for(int i=2;i<=n;i++){
		dp[i]=dp[i-1]+1;
		while(h[i]>=h[d[top1]]&&top1){
			int x=h[d[top1]];
			top1--;
			if(h[i]>x&&top1){
				dp[i]=min(dp[i],dp[d[top1]]+1);
			}
		}
		d[++top1]=i;
		while(h[i]<=h[u[top2]]&&top2){
			int x=h[u[top2]];
			top2--;
			if(h[i]<x&&top2){
				dp[i]=min(dp[i],dp[u[top2]]+1);
			}
		}
		u[++top2]=i;
	}
	cout<<dp[n]<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Phoenix_ZengHao

创作不易,能否打赏一瓶饮料?

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

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

打赏作者

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

抵扣说明:

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

余额充值