【3】Codeforces Global Round 9. D. Replace by MEX

题目

http://codeforces.com/contest/1375/problem/D
题目
题目

思路

由于每次放入的都是MEX,也就是说如果放入了MEX,则这个数不会再成为MEX(除非又被换出来)。

如果我们每次把MEX放到下标为MEX的位置,则我们可以不断把MEX归位。且不会再有同样的值来替换已经归位的数(因为它不再是MEX)。这样我们每次操作可以归位一个数。

但由于一共n+1个数,放入n个位置中,所以最大的那个数n将没有地方放。我们把最大的数放入n-1这个位置中(后来想想其实这步没有必要)。但假如n-1的位置中已经放置了n-1这个数,则我们找到一个没有被归位的位置,把n放进去。下次的MEX一定不是n,于是可以归位一个数。这样我们两次操作可以归位一个数。所以以上解法是可以在2n次操作内解决的。

每次找到MEX同时验证是否是合法解,需要一次遍历。当n无法放入n-1位置时,会再进行一次遍历。2n次操作则时间复杂度为O(n^2)。由于n最大为1000,所以已经可以解决,无需进一步优化。

代码

代码均为提交通过版本。为保持比赛时原样,没有后期优化或者修改。但为方便阅读,可能会增加注释。

#include <iostream>
#include <vector>
using namespace std;
 
int main() {
	int tcase;
	std::ios::sync_with_stdio(false);
	cin >> tcase;
	while(tcase--) {
		int n;
		cin >> n;
		int num[1002];
		for(int i = 0; i < n; i++) {
			cin >> num[i];
		}
		
		vector<int> seq;
		while(true) {
			vector<int> mask(n + 1);
			bool is_valid = true;
			// 记录哪些数出现过,并验证是否是非下降数组.
			for(int i = 0; i <n; i++) {
				mask[num[i]] = 1;
				if (i > 0) {
					if (num[i] < num[i - 1]) {
						is_valid = false;
					}
				}
			}
			if (is_valid) {
				break;
			}
			int mex;
			for(int i = 0; i <= n; i++) {
				if (mask[i] == 0) {
					mex = i;
					break;
				}
			}
			if (mex != n) {
				// 归位
				num[mex] = mex;
				seq.push_back(mex + 1);
			} else {
				if (num[n - 1] == n - 1) {
					// 找到一个还没有归位的位置放进去。
					for(int i = 0; i < n; i++) {
						if (num[i] != i) {
							num[i] = mex;
							seq.push_back(i + 1);
							break;
						}
					}
				} else {
					// 直接放入n-1的位置。也可以不要这一步,都放入没有归位的位置。
					num[n - 1] = mex;
					seq.push_back(n);
				}
			}
		}
		cout << seq.size() << endl;
		for(int i = 0; i < seq.size(); i++) {
			cout << seq[i] << " ";
		}
		cout << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值