【Codeforces Global Round 9 D】Replace by MEX

题目链接

点我呀

翻译

给你一个长度为 (n) 的数组。

你可以将某个位置上的数字换成 (mex) 最多 (2*n) 次。

让你把这个数组变成不下降的,这个数组中的数字都在 (0..n) 之间。

(mex) 表示没有出现过的最小的整数。

题解

构造题,我们可以把目标改为让最后的数组变成 (0,1,2cdots n-1)

可以这样做,一开始肯定有很多位置 (a[i]!=i) (这里 (0le ile n-1)),设每次求出来的 (mex)(tag)

那么如果 (tag<n), 则直接让 (a[tag]=tag) 即可,因为 (tag) 是没有出现过的数字,所以 (a[tag]!=tag)

这样我们就能让 (a[i]!=i) 的个数减小 (1) 了。

但是可能会出现 (tag=n) 的情况,这个时候,我们随便找个 (a[i]!=i) 的位置 (i), 让 (a[i] = tag) 就行。

则下一次的 (mex) 一定是小于 (n) 的了。

再重复让 (a[tag] = tag) 即可。

显然不会超过 (2*n) 次这样的操作。

代码

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

const int N = 1000;

int t, n;
int a[N + 10],b[N + 10];

int getMex(){
    memset(b,0,sizeof(b));
    for (int i = 0;i < n; i++){
        b[a[i]] = 1;
    }
    for (int i = 0;i <= n; i++)
        if (b[i] == 0){
            return i;
        }
    return 0;
}

int main(){
    scanf("%d",&t);
    while (t--){
        vector<int> v;
        v.clear();
        scanf("%d",&n);
        int cnt = 0;
        for (int i = 0;i < n; i++){
            scanf("%d",&a[i]);
            if (a[i] != i){
                cnt++;
            }
        }
        while (cnt > 0){
            int tag = getMex();
            if (tag < n){
                a[tag] = tag;
                v.push_back(tag+1);
                cnt--;
            }else{
                for (int i = 0;i < n; i++)
                    if (a[i] != i){
                        a[i] = tag;
                        v.push_back(i+1);
                        break;
                    }
            }
        }
        printf("%d
",(int)v.size());
        for (int i = 0;i < (int)v.size(); i++){
            printf("%d ",v[i]);
        }
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/13276820.html