[贪心][二分]Sort Zero Codeforces1712C

98 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第14天,点击查看活动详情

Problem Description

You are given an array of nn positive integers a1,a2,…,ana1,a2,…,an.

In one operation you do the following:

Choose any integer xx. For all ii such that ai=xai=x, do ai:=0ai:=0 (assign 00 to aiai). Find the minimum number of operations required to sort the array in non-decreasing order.

Input

Each test contains multiple test cases. The first line contains the number of test cases tt (1≤t≤1041≤t≤104). Description of the test cases follows.

The first line of each test case contains a single integer nn (1≤n≤1051≤n≤105).

The second line of each test case contains nn positive integers a1,a2,…,ana1,a2,…,an (1≤ai≤n1≤ai≤n).

It is guaranteed that the sum of nn over all test cases does not exceed 105105.

Output

For each test case print one integer — the minimum number of operations required to sort the array in non-decreasing order.

Example

input

5

3

3 3 2

4

1 3 1 3

5

4 1 5 3 2

4

2 4 1 2

1

1

output

1

2

4

3

0

Note

In the first test case, you can choose x=3x=3 for the operation, the resulting array is [0,0,2][0,0,2].

In the second test case, you can choose x=1x=1 for the first operation and x=3x=3 for the second operation, the resulting array is [0,0,0,0][0,0,0,0].

题意:

给出一个数组,你可以进行若干次操作,每次操作可以选择数组中某个数字x,令所有的x变成0,如果想得到一个不减序列的最少操作次数是多少。

分析:

操作次数满足二分性质,所以可以尝试一下二分,在check(x)函数中需要判断能否通过至多x次操作得到不减序列,那具体选哪几个数变成0呢?贪心地想,选择最靠前的非0数字最优,这是因为假如选择的是中间的非0数字,那么为了序列整体不减,前面的非0数字也一定要变成0,这样至少也要操作两次,但是直接选择最靠前的非0数字一定不会比这种方案差,毕竟它可以之后再选择中间的非0数字,甚至还会更优,因为这样是至少操作一次。所以贪心策略就是操作机会都用在最靠前的非0数字上,最后检查一下序列是否不减,最终复杂度为O(nlogn)。

具体代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <unordered_map>
using namespace std;
 
int a[100005], n, cpy[100005];
 
bool check(int x){
	unordered_map<int, bool> mp;
	for(int i = 1; i <= n; i++){
		if(mp.count(cpy[i]))
			cpy[i] = 0;
		else if(mp.size() < x){
			mp[cpy[i]] = true;
			cpy[i] = 0;
		}
	}
	for(int i = 2; i <= n; i++)
		if(cpy[i]-cpy[i-1] < 0) return false;
	return true;
}
 
signed main()
{
	int T;
	cin >> T;
	while(T--){
		scanf("%d", &n);
		for(int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		int l = 0, r = n, ans = -1;
		while(l <= r){
			for(int i = 1; i <= n; i++)
				cpy[i] = a[i];
			int mid = l+r>>1;
			if(check(mid)){
				ans = mid;
				r = mid-1;
			}
			else l = mid+1;
		}
		printf("%d\n", ans);
	} 
    return 0;
}