MEX Count

题目

换个角度考虑, 什么情况下对答案有贡献

一、核心条件:MEX=i 的充要条件

对于某个非负整数 i 要成为删除 k 个元素后的 MEX,必须满足两个条件(Step 2):

  1. i ≤ n−k:
    剩余元素数量为 n−k,而 MEX 不能超过数组大小(否则无法容纳 0~i-1 这些数)。例如,剩余 3 个元素的 MEX 最大为 3(如 [0,1,2])。

  2. freq(i) ≤ k:
    必须删除 i 的所有出现(否则 i 仍在数组中,MEX 会小于 i)。因此,删除的 k 至少要等于 i 的出现次数 freq(i)。

二、区间标记:每个 i 的有效 k 范围

对于每个 i(0 ≤ i ≤ mex,其中 mex 是原始数组的 MEX),其有效 k 范围是 闭区间 [L, R]:

L = freq(i)(最小删除次数,确保删完i)
R = n−i(最大删除次数,确保剩余元素足够大,容纳0~i-1)

若 L ≤ R,则 i 可以在 k ∈ [L, R] 时成为 MEX。我们通过 差分数组 标记这些区间,后续用前缀和统计每个 k 对应的有效 i 数量。

Code

点击查看代码
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAXN = 2e5 + 10;

int t;
int freq[MAXN];   // 统计每个数的出现次数
int diff[MAXN+2]; // 差分数组,用于区间标记

void solve() {
    ll n;
    cin >> n;
    memset(freq, 0, sizeof(freq)); // 重置频率数组
    
    for (int i = 1; i <= n; ++i) {
        int x;
        cin >> x;
        if (x <= n) { // 超过n的数不影响MEX计算,可忽略
            freq[x]++;
        }
    }
    
    // 步骤1:计算原始MEX(第一个未出现的非负整数)
    int mex = 0;
    while (mex <= n && freq[mex] > 0) {
        mex++;
    }
    
    // 步骤2:初始化差分数组,标记有效区间
    memset(diff, 0, sizeof(diff));
    
    // 处理 0 ~ mex-1(这些数一定存在,因为mex是第一个缺失的)
    for (int i = 0; i < mex; ++i) {
        int L = freq[i];          // 删完i至少需要删除L次
        int R = n - i;            // 剩余元素至少i个(容纳0~i-1)
        if (L > R) continue;      // 区间无效,跳过
        diff[L]++;                // 标记区间起点
        if (R + 1 <= n) {
            diff[R + 1]--;       // 标记区间终点+1
        }
    }
    
    // 处理 mex 本身(仅当剩余元素足够大时,mex可作为MEX)
    if (mex <= n) {
        int L = 0;                // 删0次即可(mex原本就不存在)
        int R = n - mex;          // 剩余元素至少mex个(容纳0~mex-1)
        diff[L]++;
        if (R + 1 <= n) {
            diff[R + 1]--;
        }
    }
    
    // 步骤3:前缀和计算每个k的MEX可能值数量
    vector<int> res(n + 1, 0);
    int current = 0;
    for (int k = 0; k <= n; ++k) {
        current += diff[k];
        res[k] = current;
    }
    
    // 输出结果
    for (int k = 0; k <= n; ++k) {
        cout << res[k] << " ";
    }
    cout << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
posted @ 2025-07-03 20:59  归游  阅读(48)  评论(0)    收藏  举报