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=fi−1+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+1⋯j−1}>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+1⋯j−1}<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;
}