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

分析:

  1. 设f[i]为到达 i 的最小步数;
  2. 考虑第二操作为,假设 j 为1~i-1中大于h[i]的最靠右的位置,那么以 j 位置开始的单调递减序列都可以一步转移到 i ,而1~j-1位置的都不能通过操作二来一步跳到 i 位置,因为有 j 位置的“阻拦”
  3. 操作三同理;
  4. 更新单调队列来维护即可
#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;
}
View Code
原文地址:https://www.cnblogs.com/starve/p/13638360.html