题解 CF2207E1 【N-MEX (Constructive Version)】

· · 题解

方便起见,令 a_0 = n, b_0 = 10^9

考虑 a_i 所能提供的信息:b_0, b_1, \cdots, b_i< a_i 的项的数量为 \text{need}_i = (a_i + 1) - (n - i + 1)。这引出了有解的第一个条件:

另外,注意到在从 a_ia_{i + 1} 的过程中,若 b_{i + 1} < a_ib_{i + 1} 没有被用过则 a_i = a_{i + 1},若 b_{i + 1} \geq a_ib_{i + 1} 被用过则 a_i > a_{i + 1}。这引出了有解的第二个条件:

当 (1)(2) 皆满足,考虑一步一步构造:

那么,只要满足 (1)(2),这一算法就一定能构造出一组解吗?事实上是可以的:

综上,时间复杂度为 O(\sum n)

代码:

#include <stdio.h>

int a[200001], b[200001];
bool mark[2000001];

void solve(){
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; i++){
        int need = (a[i] + 1) - (n - i + 1);
        if (need < 0 || need > i){
            printf("NO\n");
            return;
        }
    }
    a[0] = n;
    for (int i = 1; i <= n; i++){
        if (a[i] > a[i - 1]){
            printf("NO\n");
            return;
        }
    }
    for (int i = 0; i <= n; i++){
        mark[i] = true;
    }
    for (int i = 0; i <= n; i++){
        mark[a[i]] = false;
    }
    for (int i = 1, j = n; i <= n; i++){
        if (a[i] == a[i - 1]){
            while (j >= 0 && !mark[j]) j--;
            b[i] = j--;
        } else {
            b[i] = 1e9;
        }
    }
    printf("YES\n");
    for (int i = 1; i <= n; i++){
        printf("%d ", b[i]);
    }
    printf("\n");
}

int main(){
    int t;
    scanf("%d", &t);
    for (int cas = 1; cas <= t; cas++){
        solve();
    }
    return 0;
}