传送门
设
d
p
[
i
]
dp[i]
dp[i]表示到达第
i
i
i个城市要的最小跳跃次数,首先只看
1
、
2
1、2
1、2的转移条件,我们容易发现枚举
i
i
i的时候,一旦
a
[
i
−
1
]
<
a
[
i
]
a[i-1]<a[i]
a[i−1]<a[i],那么
d
p
[
i
−
1
]
dp[i-1]
dp[i−1]只会对
d
p
[
i
]
dp[i]
dp[i]产生贡献,因为
a
[
i
]
a[i]
a[i]阻挡了从
a
[
i
−
1
]
a[i-1]
a[i−1]往后继续跳。不过对于前面第一个
a
[
j
]
≥
a
[
i
]
a[j]\ge a[i]
a[j]≥a[i]的
j
j
j,它是最左边的一个能转移到
i
i
i的位置,对于
1
∼
j
−
1
1\sim j-1
1∼j−1的数也因为
a
[
j
]
≥
a
[
i
]
a[j]\ge a[i]
a[j]≥a[i]的原因导致无法转移到
i
i
i,不过它们存在机会转移到
i
i
i以后的位置,因此我们维护一个单调递减的栈即可,若当前元素大于栈顶元素,那么转移一下然后pop掉即可。
对于第 3 3 3个转移条件跟第 2 2 2个条件是对称的,所以再维护一个单调递增的栈即可。
int dp[maxn],a[maxn];
int up[maxn],down[maxn],totu,totd;
int main(){
int n=rd();
up[++totu]=down[++totd]=1;
a[1]=rd();
memset(dp,0x3f,sizeof(dp));
dp[1]=0;
FOR(i,2,n+1){
int u=a[i]=rd();
while(totd && u>a[down[totd]]){
dp[i]=min(dp[i],dp[down[totd--]]+1);
}
while(totu && u<a[up[totu]]){
dp[i]=min(dp[i],dp[up[totu--]]+1);
}
if(totd){
dp[i]=min(dp[i],dp[down[totd]]+1);
}
if(totu){
dp[i]=min(dp[i],dp[up[totu]]+1);
}
if(a[down[totd]]==u)totd--;
if(a[up[totu]]==u)totu--;
down[++totd]=i;
up[++totu]=i;
}
wrn(dp[n]);
}