[ cf1407D ] 单调栈初见
D. Discrete Centrifugal Jumps
题意:n栋楼,从1跳到n。每次选中一个子序列,如符合以下情况可从列头i跳到列尾j。
-
\(i = j+1\)
-
\(max(h_{i+1},\dots ,h_{j-1})<min(h_i,h_j)\)
-
\(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;
}

浙公网安备 33010602011771号