[ cf1407D ] 单调栈初见

D. Discrete Centrifugal Jumps

题意:n栋楼,从1跳到n。每次选中一个子序列,如符合以下情况可从列头i跳到列尾j。

  1. \(i = j+1\)

  2. \(max(h_{i+1},\dots ,h_{j-1})<min(h_i,h_j)\)

  3. \(min(h_{i+1},\dots ,h_{j-1})>max(h_i,h_j)\)

问最少跳几次。

题解:dp + 单调栈

从1到n遍历h。情况分为2和3.

对于2,我们用一个栈维护当前序列的下降序列,如果遇到当前的高度h大于栈顶,则更新dp并弹出栈顶,直到栈顶高度大于等于h,如果等于h,也要更新dp并弹出栈顶。

对于3,我们用一个栈维护当前序列的上升序列,其他类似情况2.

#include<bits/stdc++.h>
#define ll long long
#define pll pair<ll,ll>
#define pii pair<int,int>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define mem0(x) memset(x,0,sizeof(x))
#define meminf(x) memset(x,0x3f,sizeof(x))
#define VI vector<int>
#define VL vector<ll>
using namespace  std;

const int N = 3e5+5;
int a[N],s1[N],s2[N],scnt1,scnt2;
int dp[N];

int main(){
    ios::sync_with_stdio(0);
    int n;cin>>n;
    rep(i,1,n){
        cin>>a[i];
    }
    //build(1,1,n);
    meminf(dp);
    s1[++scnt1] = s2[++scnt2] = 1;
    dp[1] = 0;
    rep(i,2,n){
        while(scnt1>0&&a[s1[scnt1]]<a[i]){
            dp[i] = min(dp[i],dp[s1[scnt1]]+1);
            scnt1--;
        }
        if(scnt1>0){
            dp[i] = min(dp[i],dp[s1[scnt1]]+1);
            if(a[s1[scnt1]]==a[i])
                scnt1--;
        }
        s1[++scnt1] = i;
        while(scnt2>0&&a[s2[scnt2]]>a[i]){
            dp[i] = min(dp[i],dp[s2[scnt2]]+1);
            scnt2--;
        }
        if(scnt2>0){
            dp[i] = min(dp[i],dp[s2[scnt2]]+1);
            if(a[s2[scnt2]]==a[i])
                scnt2--;
        }
        s2[++scnt2] = i;
    }
    cout<<dp[n]<<endl;
}


posted @ 2020-09-09 16:55  Cha2a_zzZ  阅读(167)  评论(0)    收藏  举报