CF 1407D

单调栈 + dp 

dp蛮好想的

单调栈需要注意,此题要求i由j转移而得的条件为:

1. j == i - 1

2. i, j位置的h较小值必须大于二者之间序列内的最大值

3. i, j位置的h较大值必须小于二者之间序列内的最小值

满足任意一条即可转移

 

而 对于相同高度的元素,则不能同时出现在栈内。因为当后续节点由此部分节点进行转移时,相同高度的前一个元素是不能进行转移的。

因而必须判断,当即将加入栈内的元素与栈顶元素高度相同时,则需要将i位置的dp更新,之后将原先的栈顶元素弹出,再将新的具有相同高度的i节点加入栈中。

这也与栈的单调性保持了一致。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<stack>
 6 #include<cstdio>
 7 #define INF 0x3f3f3f3f
 8 using namespace std;
 9 const int N = 3e5 + 10;
10 
11 int n;
12 int a[N];
13 int dp[N];
14 
15 int read(){
16     char ch=getchar();int x=0,f=1;
17     while(ch<'0' || ch>'9')    {if(ch=='-')f=-1;ch=getchar();}
18     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
19     return x*f;
20 }
21 stack<int> s1, s2;//up, down
22 int main(){
23     n = read();
24     for(register int i = 1 ; i <= n ; i++){
25         a[i] = read();
26         dp[i] = INF;
27     }
28     dp[1] = 0;
29     s1.push(1);
30     s2.push(1);
31     for(register int i = 2 ; i <= n ; i++){
32         //递减栈 
33         while(!s1.empty() && a[s1.top()] < a[i]){
34             dp[i] = min(dp[i], dp[s1.top()] + 1);
35             s1.pop();
36         }
37         if(int(s1.size())){    
38             dp[i] = min(dp[i], dp[s1.top()] + 1);
39             if(a[i] == a[s1.top()]){//严格保持栈的单调性    
40                 s1.pop();
41             //若存在两个相同高度的块,后更新dp实际上不可更新前一个高度  4 3 3 : i = 2 ?只能更新后面那个3    
42             }
43         }
44         s1.push(i);
45         
46         //递增栈 
47         while(!s2.empty() && a[s2.top()] > a[i]){
48             dp[i] = min(dp[i], dp[s2.top()] + 1);
49             s2.pop();
50         }
51         if(int(s2.size())){
52             dp[i] = min(dp[i], dp[s2.top()] + 1);            
53             if(a[i] == a[s2.top()]){
54                 s2.pop();
55             }
56         }
57         s2.push(i);
58     }
59     printf("%d\n",dp[n]);
60     
61     return 0;
62 }

 

posted @ 2020-11-07 19:47  LegendN  阅读(102)  评论(0编辑  收藏  举报