D. Discrete Centrifugal Jumps(单调队列)
题:https://codeforces.com/contest/1407/problem/D
题意:给定n个数的高度,若位置 i 能跳到位置 j 得满足以下任一条件:
- i+1=j
- max(hi+1,…,hj−1)<min(hi,hj)
- max(hi,hj)<min(hi+1,…,hj−1)
问最少多少步能从1到n
分析:
- 设f[i]为到达 i 的最小步数;
- 考虑第二操作为,假设 j 为1~i-1中大于h[i]的最靠右的位置,那么以 j 位置开始的单调递减序列都可以一步转移到 i ,而1~j-1位置的都不能通过操作二来一步跳到 i 位置,因为有 j 位置的“阻拦”
- 操作三同理;
- 更新单调队列来维护即可
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define pii pair<int,int> typedef long long ll; const int mod=1e9+7; const int M=1e6+6; const int inf=0x3f3f3f3f; const ll INF=1e18; int h[M],dp[M],f[M],down[M],up[M]; int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&h[i]); down[1]=1,up[1]=1; int totd=1,totu=1; memset(f,0x3f,sizeof(f)); f[1]=0; for(int i=2;i<=n;i++){ while(totd>0&&h[i]>h[down[totd]]) f[i]=min(f[i],f[down[totd--]]+1); while(totu>0&&h[i]<h[up[totu]]) f[i]=min(f[i],f[up[totu--]]+1); f[i]=min(f[i],f[down[totd]]+1); f[i]=min(f[i],f[up[totu]]+1); if(h[down[totd]]==h[i]) totd--; if(h[up[totu]]==h[i]) totu--; down[++totd]=i; up[++totu]=i; } printf("%d",f[n]); return 0; }