CodeForces - 1407D Discrete Centrifugal Jumps (单调栈 + dp)

There are nn beautiful skyscrapers in New York, the height of the ii-th one is hihi. Today some villains have set on fire first n−1n−1 of them, and now the only safety building is nn-th skyscraper.

Let's call a jump from ii-th skyscraper to jj-th (i<ji<j) discrete, if all skyscrapers between are strictly lower or higher than both of them. Formally, jump is discrete, if i<ji<j and one of the following conditions satisfied:

  • i+1=ji+1=j
  • max(hi+1,…,hj−1)<min(hi,hj)max(hi+1,…,hj−1)<min(hi,hj)
  • max(hi,hj)<min(hi+1,…,hj−1)max(hi,hj)<min(hi+1,…,hj−1).

At the moment, Vasya is staying on the first skyscraper and wants to live a little longer, so his goal is to reach nn-th skyscraper with minimal count of discrete jumps. Help him with calcualting this number.

Input

The first line contains a single integer nn (2≤n≤3⋅1052≤n≤3⋅105) — total amount of skyscrapers.

The second line contains nn integers h1,h2,…,hnh1,h2,…,hn (1≤hi≤1091≤hi≤109) — heights of skyscrapers.

Output

Print single number kk — minimal amount of discrete jumps. We can show that an answer always exists.

Examples

Input

5
1 3 1 4 5

Output

3

Input

4
4 2 2 4

Output

1

Input

2
1 1

Output

1

Input

5
100 1 100 1 100

Output

2

Note

In the first testcase, Vasya can jump in the following way: 1→2→4→51→2→4→5.

In the second and third testcases, we can reach last skyscraper in one jump.

Sequence of jumps in the fourth testcase: 1→3→51→3→5.

题意:

一个人需要从第 1 栋楼跳到第 n 栋楼,每栋楼有个高度 h[i],每次只能进行以下三种跳跃之一:

(1)从 i - 1 跳到 i

(2)从 j 跳到 i ,且 j 和 i 之间楼的高度 < min(h[j], h[i])

(3)从 j 跳到 i ,且 j 和 i 之间楼的高度 > max(h[j], h[i])

问最少跳多少次

思路:

单调栈维护第 i 栋楼可以从之前的哪些楼跳过来。单增栈维护第(3)种跳跃方式,单减栈维护第(2)种跳跃方式,再加上每一栋楼都可以从前一栋楼跳过来。于是对于任意一对 j、 i,j 可以跳到 i,有转移方程dp[i] = min(dp[i], dp[j] + 1)

(以单增栈为例)一个未进栈的高度可以由当前栈顶比它大的高度转移过来,然后pop掉这些比它大的高度,如果遇到相同的高度,只能由栈顶的这个相同高度转移过来,虽然当前栈顶和栈顶的下一个高度相同,但是可能在原序列中它们并不是相邻的,比如原序列 2 3 4 5 2 2,当前栈:2 2,下一个进栈高度:2,栈中这两个2之间原本存在3 4 5,即原序列最后一个2不可以从第一个2转移过来。所以相同高度只能转移一个,并且还要在转移之后把相同高度全部pop掉。

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 3e5+7;
int a[maxn];

int dp[maxn];

int main()
{
	int n;
	cin >> n;
	for(int i = 1;  i<= n; i++){
		scanf("%d", &a[i]);
	}
	memset(dp, inf, sizeof(dp));
    stack<int> st1, st2;
	dp[1] = 0;
	st1.push(1), st2.push(1);
	for(int i = 2;  i <= n; i++) {
        dp[i] = min(dp[i], dp[i - 1] + 1);
        ///单增栈
		while(!st1.empty() && a[st1.top()] > a[i]) {
            dp[i] = min(dp[i], dp[st1.top()] + 1);
			st1.pop();
		}
		if(!st1.empty())
            dp[i] = min(dp[i], dp[st1.top()] + 1);
        while(!st1.empty() && a[st1.top()] == a[i]) st1.pop();
		st1.push(i);
        ///单减栈
		while(!st2.empty() && a[st2.top()] < a[i]) {
            dp[i] = min(dp[i], dp[st2.top()] + 1);
			st2.pop();
		}
		if(!st2.empty())
            dp[i] = min(dp[i], dp[st2.top()] + 1);
        while(!st2.empty() && a[st2.top()] == a[i]) st2.pop();
		st2.push(i);
	}
	cout << dp[n] << endl;
}

猜你喜欢

转载自blog.csdn.net/weixin_43871207/article/details/108754221