1 条题解

  • 0
    @ 2026-4-15 18:34:23

    A. Submission is All You Need —— 详细题解


    题目重述

    你有一个多重集 SS,包含 nn 个非负整数。初始得分为 00。可以执行以下两种操作任意次(顺序任意):

    1. 选择当前 SS 的一个子集 SS',将 sum(S)\text{sum}(S') 加到得分,然后删除 SS'
    2. 选择当前 SS 的一个子集 SS',将 mex(S)\text{mex}(S') 加到得分,然后删除 SS'

    求能获得的最大可能得分。

    其中:

    • sum(T)\text{sum}(T) = TT 中所有元素的和
    • mex(T)\text{mex}(T) = 不在 TT 中的最小非负整数

    数据范围:

    • 1n501 \le n \le 50
    • 0Si500 \le S_i \le 50
    • 1t1031 \le t \le 10^3

    关键观察

    观察 1:数值 00 的特殊性

    对于只包含 00 的子集:

    • sum({0})=0\text{sum}(\{0\}) = 0,加 00 分没有意义
    • mex({0})=1\text{mex}(\{0\}) = 1,无论有多少个 00,一次操作就能得 11

    因此,所有 00 应该通过一次 mex\text{mex} 操作处理,得 11 分。

    观察 2:数值 x>0x > 0 的处理

    对于只包含 xx 的子集(假设 x1x \ge 1):

    • sum({x})=x1\text{sum}(\{x\}) = x \ge 1,得 xx
    • mex({x})=0\text{mex}(\{x\}) = 0(因为 00 不在集合中),得 00

    显然,用 sum\text{sum} 操作更好。

    观察 3:组合操作

    对于包含多个不同数值的子集:

    • 如果包含 00mex\text{mex} 可能得到 11 或更大的值,但不会超过 11(因为 11 通常也存在)
    • 实际上,把数值分开处理总是最优的

    最优策略

    1. 处理 00:如果存在 00,用一次 mex\text{mex} 操作取走所有 00,得 11
    2. 处理 x1x \ge 1:对每个数值 xx,用一次 sum\text{sum} 操作取走所有值为 xx 的元素,得 x×cnt[x]x \times \text{cnt}[x]

    因此:

    $$\text{ans} = [\text{cnt}[0] > 0] + \sum_{x=1}^{50} x \cdot \text{cnt}[x] $$

    正确性证明

    为什么分开处理是最优的?

    1. 任何包含 00 和其他数的子集,mex\text{mex} 至少为 11,但最多不会超过 11(因为 11 要么存在要么不存在)。而用 sum\text{sum} 处理其他数能获得更多分。

    2. 对于 x1x \ge 1,如果混在一起用 sum\text{sum},得到的是它们的和,等于分开用 sum\text{sum} 的和。分开处理不会损失分数。

    3. 如果试图用 mex\text{mex} 处理 x1x \ge 1,只能得到 0011 分,远小于 x1x \ge 1

    4. 因此,最优策略就是:

      • 把所有 00 打包,用一次 mex\text{mex}11
      • 把每个正数分别打包,用 sum\text{sum} 得自身分数

    代码实现

    #include <bits/stdc++.h>
    using namespace std;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int t;
        cin >> t;
        
        while (t--) {
            int n;
            cin >> n;
            
            vector<int> cnt(51, 0);  // 统计每个数出现次数
            for (int i = 0; i < n; i++) {
                int x;
                cin >> x;
                cnt[x]++;
            }
            
            long long ans = 0;
            
            // 如果有 0,用一次 mex 操作得 1 分
            if (cnt[0] > 0) ans++;
            
            // 处理正数:用 sum 操作
            for (int x = 1; x <= 50; x++) {
                ans += (long long)x * cnt[x];
            }
            
            cout << ans << '\n';
        }
        
        return 0;
    }
    

    复杂度分析

    • 时间复杂度:O(n+50)O(n + 50) 每个测试用例
    • 空间复杂度:O(50)O(50)

    样例验证

    样例 1

    n=3, S={0,1,1}
    cnt[0]=1 → ans += 1
    cnt[1]=2 → ans += 1×2 = 2
    总得分 = 3 ✓
    

    样例 2

    n=3, S={1,2,3}
    cnt[0]=0 → ans += 0
    cnt[1]=1 → ans += 1
    cnt[2]=1 → ans += 2
    cnt[3]=1 → ans += 3
    总得分 = 6 ✓
    

    总结

    要点 说明
    核心思想 贪心:00mex\text{mex},正数用 sum\text{sum}
    时间复杂度 O(n)O(n) 每个测试用例
    难度 *800,约 3.0/10 分
    • 1

    信息

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