2020 ICPC 沈陽 The 2020 ICPC Asia Shenyang Regional Programming Contest F. Kobolds and Catacombs.(離散化/樹狀數組/好題)


Kobolds are rat-like, candle-loving cave folk, digging deep beneath the surface for millennia. Today, they gather together in a queue to explore yet another tunnel in their catacombs!

But just before the glorious movement initiates, they have to arrange themselves in non-descending heights. The shortest is always the leader digging small holes, and the followers swelling it.

The kobolds are hyperactive; they like to move here and there. To make the arrangement easier, they decide to group themselves into consecutive groups first, then reorder in each group.

What's the maximum number of consecutive groups they can be partitioned into, such that after reordering the kobolds in each group in non-descending order, the entire queue is non-descending?

For example, given a queue of kobolds of heights [1, 3, 2, 7, 4], we can group them into three consecutive groups ([1] [3, 2] [7, 4]), such that after reordering each group, the entire queue can be non-descending.

Input

The first line of the input contains a single integer 𝑛n (1≤𝑛≤106), denoting the number of kobolds.

The second line contains n integers a1,a2,…,an (1≤𝑎𝑖≤109), representing the heights of the kobolds in the queue.

Output

Print a single integer, denoting the maximum number of groups.

Example

input

Copy

5
1 3 2 7 4

output

Copy

3

更新:貌似是數據水了,下面的代碼能被牛客重現賽評論區的一個數據hack掉qaq

大意就是問最多將這個序列分成多少段,使得每段分別從小到大排序后整個序列是單調不減的。

只會sb解法QAQ。首先將原數組離散化,本質上就是看最多能分成多少段,使得每段是排序后單調不減的(離散化后每段是稠密的,即排序后相鄰數相差不超1),同時兩段之間是單調不減的。

首先對離散化后的序列進行遍歷,用樹狀數組維護區間覆蓋的情況,同時要注意幾種特殊的情況。詳情見代碼:

#include <bits/stdc++.h>
#define int long long
//bit要用到前綴和 因此要define int long long
#define N 1000002
using namespace std;
int n, a[N];
vector<int> v;
int b[N];
void add(int x, int y) {
	for(; x <= N; x += (x & -x)) b[x] += y;
}
int ask(int x) {
	int ans = 0;
	for(; x; x -= (x & -x)) {
		ans += b[x];
	}
	return ans;
}
int mx_pos[N];
signed main() {
	cin >> n;
	for(int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		v.push_back(a[i]);
	}
	//離散化
	sort(v.begin(), v.end());
	vector<int>::iterator it = unique(v.begin(), v.end());
	v.erase(it, v.end());
	for(int i = 1; i <= n; i++) {
		a[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
		mx_pos[a[i]] = i;
	}

	int mx = 0, premx = 0;//當前段最大值 上一個段的最大值
	int i = 1;
	int ans = 0;
	while(i < n) {
		if(ask(a[i]) - ask(a[i] - 1) == 0) add(a[i], 1);//首先進行更新
		mx = max(mx, a[i]);
		if(i < mx_pos[premx] && a[i] != premx) {//對應於1 1 2 3 4 1這種樣例,如果當前處於i = 3的位置就應該跳過,如果處於i = 2的位置則不能跳過
			//mx_pos[x]是x這個數出現的最后位置,比如上一行的樣例mx_pos[1] = 6
			i++;
			continue;
		}
		int cnt = ask(mx) - ask(premx);//統計當前段最大值到上一個段最大值+1的這段區間是否被覆蓋完全
		if(cnt == mx - premx) {//如果已經被覆蓋完全
			if(i + 1 <= n && a[i + 1] < mx) {//對應於1 2 3 1這種情況如果當前i = 3,此時也算是覆蓋完全,但后面的1必須算入當前段
				i++;
			} else {//找到了當前段的終點
				ans++;
				premx = mx;
				mx = 0;
				i++;
			}
		} else {//沒有被覆蓋完全,繼續循環
			i++;
		}
	}
	cout << ans + 1;//別忘加上最后一個段(前面代碼到n就停了
	return 0;
}
// 7
// 1 5 2 3 3 6 4
//每一段必須是連續的 比如2 3 3 4 且5 2 3 4 2 2這樣的一定要把最后的2也算進去

// 5
// 1 2 3 4 1

// 6
// 1 1 1 1 2 1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM