1 条题解

  • 0
    @ 2026-4-2 16:04:22

    题目题解

    问题理解

    给定长度为 nn 的数组 aa(元素值在 [0,n][0, n] 之间)。
    对于每个 k=0,1,,nk = 0, 1, \dots, n,统计从 aa恰好移除 kk 个元素后,剩余数组的 MEX 可能取值的个数。


    第一步:原始 MEX

    mm 为原数组的 MEX。即:

    m=MEX(a).m = \operatorname{MEX}(a).

    由于移除元素只能移除某些值,不能引入新值,因此剩余数组的 MEX 一定 m\le m
    此外,MEX 不能超过剩余数组的长度。设剩余数组长度为 nkn - k,则

    MEXnk.\text{MEX} \le n - k.

    第二步:MEX 等于某个 ii 的条件

    考虑 0im0 \le i \le m
    要使剩余数组的 MEX 等于 ii,必须:

    1. 所有小于 ii 的数在剩余数组中至少出现一次(这样 ii 才是最小的缺失值)。
    2. 数字 ii 在剩余数组中不出现(因为缺失它)。

    由于原数组中每个小于 ii 的数都至少出现一次(否则 mim \le i),我们可以保留它们各一个。
    要确保 ii 不出现,必须移除所有 ii 的实例。设 freq(i)\text{freq}(i)ii 在原数组中的出现次数,则

    kfreq(i).k \ge \text{freq}(i).

    此外,剩余数组长度为 nkn - k,其中我们已经保留了 ii 个不同的数(0,1,,i10,1,\dots,i-1),因此

    nkikni.n - k \ge i \quad \Rightarrow \quad k \le n - i.

    所以 ii 可行的条件是:

    freq(i)kni.\text{freq}(i) \le k \le n - i.

    第三步:充分性证明

    若上述条件成立,我们可以构造剩余数组如下:

    • 从每个 0,1,,i10,1,\dots,i-1 中保留一个元素(共 ii 个)。
    • 从剩余元素(不包括 ii)中任意选择 nkin - k - i 个,保证总数达到 nkn - k

    由于 freq(i)k\text{freq}(i) \le k,我们移除了所有 ii,且剩余元素足够多(因为 nkin - k \ge i),因此构造可行。


    第四步:差分数组方法

    anskans_k 为移除 kk 个元素后可能的 MEX 值的个数。

    对于每个 ii0im0 \le i \le m),它对 anskans_k 的贡献是:当 kk 在区间 [freq(i),ni][\text{freq}(i), n - i] 内时,ii 是可行的。

    因此我们可以用差分数组 diffdiff 来统计:

    • k=freq(i)k = \text{freq}(i)+1+1(开始可行)
    • k=ni+1k = n - i + 11-1(结束可行)

    初始 diffdiff 全为 00
    对所有 i=0,1,,mi = 0, 1, \dots, m 执行:

    $$diff[\text{freq}(i)] \mathrel{+}= 1, \quad diff[n - i + 1] \mathrel{-}= 1. $$

    然后前缀和得到 anskans_k

    ansk=j=0kdiff[j].ans_k = \sum_{j=0}^k diff[j].

    注意 i>mi > m 时,由于原数组中缺少 mm,不可能使 MEX 大于 mm,因此不考虑。


    最终算法

    1. 统计每个值的出现次数 freq[v]\text{freq}[v]
    2. 找到原数组的 MEX mm(最小的未出现值)。
    3. 初始化差分数组 diffdiff 长度为 n+2n+2
    4. i=0i = 0mm
      • $diff[\text{freq}[i]] \leftarrow diff[\text{freq}[i]] + 1$
      • diff[ni+1]diff[ni+1]1diff[n - i + 1] \leftarrow diff[n - i + 1] - 1
    5. 计算前缀和得到 ans0,,ansnans_0, \dots, ans_n,并输出。

    时间复杂度

    • 统计频率:O(n)O(n)
    • 处理 m+1m+1iiO(m)O(m)
    • 总复杂度 O(n)O(n),满足 n2×105\sum n \le 2\times 10^5

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    
    void solve() {
        int n;
        cin >> n;
        vector<int> a(n);
        vector<int> freq(n + 1, 0);
        for (int i = 0; i < n; i++) {
            cin >> a[i];
            if (a[i] <= n) freq[a[i]]++;
        }
        
        // 找到原数组的 MEX
        int mex = 0;
        while (freq[mex] > 0) mex++;
        
        // 差分数组
        vector<int> diff(n + 2, 0);
        for (int i = 0; i <= mex; i++) {
            diff[freq[i]]++;
            diff[n - i + 1]--;
        }
        
        // 前缀和得到答案
        vector<int> ans(n + 1, 0);
        int cur = 0;
        for (int k = 0; k <= n; k++) {
            cur += diff[k];
            ans[k] = cur;
        }
        
        // 输出
        for (int k = 0; k <= n; k++) {
            cout << ans[k] << (k == n ? "\n" : " ");
        }
    }
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int t;
        cin >> t;
        while (t--) {
            solve();
        }
        
        return 0;
    }
    

    验证样例

    对于第一个测试用例:

    • n=5n=5, a=[1,0,0,1,2]a = [1,0,0,1,2]
    • freq[0]=2\text{freq}[0]=2, freq[1]=2\text{freq}[1]=2, freq[2]=1\text{freq}[2]=1, freq[3]=0\text{freq}[3]=0m=3m=3
    • i=0i=0: diff[2]++diff[2]++, diff[50+1=6]diff[5-0+1=6]--
      i=1i=1: diff[2]++diff[2]++, diff[51+1=5]diff[5-1+1=5]--
      i=2i=2: diff[1]++diff[1]++, diff[52+1=4]diff[5-2+1=4]--
      i=3i=3: diff[0]++diff[0]++, diff[53+1=3]diff[5-3+1=3]--

    计算前缀和得到: ans=[1,2,4,3,2,1]ans = [1, 2, 4, 3, 2, 1],与样例一致。


    总结

    本题的关键在于:

    1. 将问题转化为对每个 ii 判断 kk 的可行区间 [freq(i),ni][\text{freq}(i), n-i]
    2. 使用差分数组高效维护 anskans_k 的变化。
    3. 注意 MEX 不能超过原始 MEX 和剩余数组长度。
    • 1

    信息

    ID
    6240
    时间
    1000ms
    内存
    256MiB
    难度
    3
    标签
    递交数
    1
    已通过
    1
    上传者