Description
给定一个序列,每次可以从 (i) 跳到 (j (>i)) 当且仅当满足以下三个条件之一:
-
(i+1=j)
-
(max(h[i+1,j-1])<min(h_i,h_j))
-
(min(h[i+1,j-1])>max(h_i,h_j))
求从下标为 (1) 的位置跳到下标为 (n) 的位置花费的最小步数。
Solution
考虑 dp,设 (f_i) 表示跳到第 (i) 个格子的最小步数,那么很显然 (f_i) 序列一定是单调的,这是由第一个转移条件保证的。
先考虑第二个条件,分析 (i) 状态可以从哪些状态转移过来。
维护一个单调递减的栈,那么有且仅有加入 (i) 的弹栈过程中经历的所有栈顶是合法的 (j)。
所以我们只需要在加入 (i) 的过程中,对每次弹栈后的栈顶 (j),做一次 (j o i) 的转移即可。
对第三个条件也是同理的。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
int n;
int a[N],f[N];
int staAsc[N],topAsc,staDec[N],topDec;
signed main()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
f[0]=1e9;
f[1]=0;
staAsc[++topAsc]=1;
staDec[++topDec]=1;
for(int i=2;i<=n;i++)
{
f[i]=f[i-1]+1;
while(topAsc && a[staAsc[topAsc]]>=a[i])
{
--topAsc;
if(a[staAsc[topAsc+1]]==a[i]) continue;
f[i]=min(f[i], f[staAsc[topAsc]]+1);
}
staAsc[++topAsc]=i;
while(topDec && a[staDec[topDec]]<=a[i])
{
--topDec;
if(a[staDec[topDec+1]]==a[i]) continue;
f[i]=min(f[i], f[staDec[topDec]]+1);
}
staDec[++topDec]=i;
}
cout<<f[n]<<endl;
return 0;
}