2021.05.04 日常总结兼一些好题的记录(六)

25 篇文章 0 订阅
3 篇文章 0 订阅

CF1407D   Discrete   Centrifugal   Jumps \color{green}{\texttt{CF1407D Discrete Centrifugal Jumps}} CF1407D Discrete Centrifugal Jumps

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

在这里插入图片描述
copy from luogu

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

很容易想到 dp,记 f i f_{i} fi 表示从 1 1 1 i i i 最少需要几步,显然 f 1 = 0 f_{1}=0 f1=0

第一个条件等价于下面一个方程:

f i = f i − 1 + 1 f_{i}=f_{i-1}+1 fi=fi1+1

考虑第 2 2 2 个条件怎么办。

因为 min ⁡ ( h i , h j ) ≤ h i \min(h_{i},h_{j}) \leq h_{i} min(hi,hj)hi,所以当 max ⁡ { h i + 1 ⋯ j − 1 } > h i \max \{ h_{i+1 \cdots j-1} \}>h_{i} max{hi+1j1}>hi 时,第二个条件一定不被满足(注意,为了叙述的方便,在下面的讨论中,我们认为 j < i j<i j<i,即从 j j j 转移到 i i i)。

i i i 往前找,遍历每一个 h j < h i h_{j}<h_{i} hj<hi 的点,当出现一个点 j j j 满足 max ⁡ { h i + 1 ⋯ j − 1 } < h j \max \{ h_{i+1 \cdots j-1} \}<h_{j} max{hi+1j1}<hj 则一定可以从点 j j j 跳到点 i i i

如何找出这样的点 j j j 呢?很简单,我们可以用一个单调栈维护即可。

3 3 3 个条件同理即可。

[code] \color{blue}{\texttt{[code]}} [code]

const int N=3e5+100;
int h[N],n,ans,f[N];
int s1[N],top1,s2[N],top2;
int main(){
	n=read();ans=n-1;
	for(int i=1;i<=n;i++)
		h[i]=read();
	f[0]=0x3f3f3f3f;f[1]=0;
	s1[top1=1]=s2[top2=1]=1;
	for(int i=2;i<=n;i++){
		f[i]=f[i-1]+1;//init
		while (top1&&h[i]<=h[s1[top1]]){
			if (h[i]!=h[s1[top1]])
				f[i]=min(f[i],f[s1[top1-1]]+1);
			--top1;
		}
		while (top2&&h[i]>=h[s2[top2]]){
			if (h[i]!=h[s2[top2]])
				f[i]=min(f[i],f[s2[top2-1]]+1);
			--top2;
		}
		s1[++top1]=s2[++top2]=i;
	}
	printf("%d",f[n]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值