cf1208B B. Uniqueness

B. Uniqueness
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given an array a1,a2,…,an. You can remove at most one subsegment from it. The remaining elements should be pairwise distinct.

In other words, at most one time you can choose two integers l and r (1≤l≤r≤n) and delete integers al,al+1,…,ar from the array. Remaining elements should be pairwise distinct.

Find the minimum size of the subsegment you need to remove to make all remaining elements distinct.

Input
The first line of the input contains a single integer n (1≤n≤2000) — the number of elements in the given array.

The next line contains n spaced integers a1,a2,…,an (1≤ai≤109) — the elements of the array.

Output
Print a single integer — the minimum size of the subsegment you need to remove to make all elements of the array pairwise distinct. If no subsegment needs to be removed, print 0.

Examples
input

3
1 2 3
output
0
input
4
1 1 2 2
output
2
input
5
1 4 1 4 9
output
2
Note
In the first example all the elements are already distinct, therefore no subsegment needs to be removed.

In the second example you can remove the subsegment from index 2 to 3.

In the third example you can remove the subsegments from index 1 to 2, or from index 2 to 3, or from index 3 to 4.
题意: 给出n个数字,找出最小的一端连续区间进行删除操作,使其剩余元素不含重复元素,求要删除的最小区间长度。
思路: 逆向考虑问题,要删除的最少区间长度对应最多能保留多少个数,又因为区间要是连续的,所以只能删除左端区间,或中区间,或右边区间。利用两个map,第一个存从左往右能保留的每个元素的下标,并用一个数记录最终下标;第二个map从右往左扫描,用于记录当前元素的右半部分能保留多少数,如果出现与其右部分的重复元素,则计算其中间要删除的元素个数,并判断是否要更新答案,否则进行标记,若当前右半部分的元素与一开始左半部分的元素,则模拟对左半部分元素删除操作,同时更新删除元素个数找出最佳答案,具体情况看代码和注释。

#include 
using namespace std;
map book1, book2;
int main() {
	int n;
	int a[2005];
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	int ans = 99999;
	// p记录左半部分能保留数字的下标(即个数), q记录右半部分能保留到的下标,q-p则为要删除的序列的大小 
	int p = 1, q = n; 
	// 从左往右扫描,记录从左往右能保留多少个数,即遇到重复数字停止扫描 
	while (p <= n) {
		if (book1[a[p]]) {
			break;
		} else {
			book1[a[p]] = p;
		}
		p++;
	}
	// 由于扫描的时候是判断下一位,所以p要减一才是实际最后那个不重复元素的下标(个数) 
	p--;
	ans = n - p; // 此时要删除的元素为元素总个数减去前左半部分要保留的数字 
	// 从右往左扫描 
	while (q >= 1) {
		if (book2[a[q]]) { // 如果q右半部分的数字在左半部分没出现过,但q右半部分的数字出现重复,则进行判断后结束扫描 
			if (ans > q - p) ans = q - p; // 如果此时要删除的元素个数比之前少,则更新答案 
			break;
		} else { // 否则进行标记该元素出现过 
			book2[a[q]] = 1;
		}
		if (book1[a[q]] && p >= book1[a[q]]) { // 如果右半部分的最左端的元素与一开始左半部分要保留的数字重复,
		//则模拟左半部分元素删除操作,同时判断是否要更新答案和更新左半部分要保留的数字下标 
			if (ans > q - p) ans = q - p;
			p = book1[a[q]] - 1;
		}
		q--;
	} 
	printf("%d\n", ans);
	return 0;
}

你可能感兴趣的:(codeforces)