1 条题解

  • 0
    @ 2026-5-14 16:56:15

    1965A - Everything Nim 官方标程思路 题解

    一、标程核心思路翻译与讲解

    1. 游戏规则

    • 每次选择 kk,满足 kk \le 最小非空堆的大小
    • 所有非空堆同时移除 kk 个石子
    • 无法操作者输,Alice 先手

    2. 标程关键推导

    1. 若最小堆大小 = 11 玩家只能选 k=1k=1,所有堆减 11,交换先手,重复直到最小堆 2\ge 2

    2. 若最小堆大小 x2x \ge 2 当前先手必胜

      • k=xk=x 可直接让对手进入必败态
      • 即使不行,选 k=x1k=x-1 强制对手只能选 k=1k=1,依然必胜

    3. 标程最终结论(最核心)

    只需要计算两个值:

    • aa:石子堆的最大值
    • bb正整数的 MEX(最小的、没出现在石子堆中的正整数)

    胜负判断:

    1. b>ab > a 游戏会一直被迫选 k=1k=1 直到结束,aa 的奇偶性决定胜负

      • aa 奇数 → Alice 胜
      • aa 偶数 → Bob 胜
    2. bab \le a 游戏会进入最小堆 2\ge 2 的先手必胜态,bb 的奇偶性决定胜负

      • bb 奇数 → Alice 胜
      • bb 偶数 → Bob 胜

    二、MEX(最小未出现正整数)计算方法

    例子:

    • [3,3,3][3,3,3] \rightarrow 没出现的最小正整数是 1b=11 \Rightarrow b=1
    • [1,7][1,7] \rightarrow 没出现的最小正整数是 2b=22 \Rightarrow b=2
    • [1,2,3][1,2,3] \rightarrow 没出现的最小正整数是 4b=44 \Rightarrow b=4

    计算方法:

    1. 数组去重 + 排序
    2. 11 开始找第一个缺失的数

    三、C++ AC 代码(对标标程,O(nlogn)O(n\log n)

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    typedef long long ll;
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        
        int t;
        cin >> t;
        while (t--) {
            int n;
            cin >> n;
            vector<ll> a(n);
            ll max_a = 0;
            
            for (int i = 0; i < n; ++i) {
                cin >> a[i];
                max_a = max(max_a, a[i]);
            }
            
            // 去重 + 排序,求 MEX(最小未出现正整数 b)
            sort(a.begin(), a.end());
            a.erase(unique(a.begin(), a.end()), a.end());
            
            ll mex = 1;
            for (ll x : a) {
                if (x == mex) mex++;
                else break;
            }
            
            // 标程核心判断
            if (mex > max_a) {
                // 看最大值的奇偶
                if (max_a % 2 == 1) cout << "Alice\n";
                else cout << "Bob\n";
            } else {
                // 看 mex 的奇偶
                if (mex % 2 == 1) cout << "Alice\n";
                else cout << "Bob\n";
            }
        }
        return 0;
    }
    

    四、样例输入输出验证

    输入

    7
    5
    3 3 3 3 3
    2
    1 7
    7
    1 3 9 7 4 2 100
    3
    1 2 3
    6
    2 1 3 4 2 4
    8
    5 7 2 9 6 3 3 2
    1
    1000000000
    

    输出

    Alice
    Bob
    Alice
    Alice
    Bob
    Alice
    Alice
    

    完全正确!


    五、复杂度说明

    • 时间:O(nlogn)O(n\log n)(排序)
    • 空间:O(n)O(n)
    • 满足题目限制:n2×105n \le 2 \times 10^5t104t \le 10^4

    六、标程核心公式总结

    • a=max(ai)a = \max(a_i)

    • b=MEX({ai},exclude 0)b = \text{MEX}(\{a_i\}, \text{exclude } 0)

    • b>ab > aa%2==1\boldsymbol{a \% 2 == 1} → Alice

    • 否则:b%2==1\boldsymbol{b \% 2 == 1} → Alice

    • 1

    信息

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