1 条题解

  • 0
    @ 2026-6-19 10:31:03

    📝 题目大意

    给定 NN 个球,每个球上写有一个整数 AiA_i。可以修改任意球上的整数,目标使所有球上整数的种类数不超过 KK。求最少需要修改多少个球。

    💡 解题思路

    1. 题目分析:题目本质是"保留不超过 KK 种数字,把其余数字的球全部改掉"。修改一个球时,可以将其改为任意值(包括已有的 KK 种之一),因此修改代价就是该球所属数字种类的出现次数。要使修改次数最少,应该保留出现次数最多的 KK 种数字,把其余数字对应的球全部改掉。

    2. 算法推导

      • 首先统计每种数字的出现次数(频率)。由于 1AiN1 \leq A_i \leq N,可以直接用大小为 NN 的数组 a 作为桶,a[x] 表示数字 xx 的出现次数。
      • 将频率数组按从大到小排序(sort(a.rbegin(), a.rend()))。
      • 排序后,前 KK 个元素就是出现次数最多的 KK 种数字的频率,应保留不动。
      • 从第 KK 个位置开始(下标 KK),所有后续元素的频率之和即为需要修改的球数——因为这些数字种类要么被淘汰,要么从未出现(频率为 00,累加也不影响结果)。
      • 最终答案 ans = sum(a[K] ... a[N-1])
    3. 边界与细节

      • KK \geq 实际不同数字种类数时,无需修改任何球,答案为 00。此时从 KK 开始累加的全是 00,算法自然得出 00,无需特判。
      • 输入中的 AiA_i 范围是 1N1 \sim N,而桶数组索引从 00 开始,因此代码中 b-- 将值映射到 [0,N1][0, N-1]
      • 桶数组大小设为 NN 足够覆盖所有可能值(因为 AiNA_i \leq N)。
      • NN 最大 2×1052 \times 10^5,答案不会超过 NN,用 int 即可。

    ⏱️ 复杂度分析

    • 时间复杂度:统计频率遍历 NN 个输入,O(N)O(N);排序频率数组,O(NlogN)O(N \log N);累加求和,O(N)O(N)。总体 O(NlogN)O(N \log N)
    • 空间复杂度:频率数组 a 大小为 NNO(N)O(N)

    💻 标准代码 (C++)

    #include <bits/stdc++.h>
    using namespace std;
    int main(){
        int n, k; 
        cin >> n >> k;
        // a[i] 表示数字 i(0-indexed)的出现次数,大小设为 n 足够
        vector<int> a(n, 0);
        for(int i = 0; i < n; i++){
            int b; 
            cin >> b;
            b--;          // 将 1-indexed 转为 0-indexed
            a[b]++;       // 统计每种数字的出现次数
        }
        // 按频率从大到小排序
        sort(a.rbegin(), a.rend());
        int ans = 0;
        // 保留前 K 个最频繁的数字,从第 K 个开始的所有频率之和即为需要修改的球数
        for(int i = k; i < n; i++) ans += a[i];
        cout << ans << endl;
        return 0;
    }
    
    • 1

    信息

    ID
    861
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者