题目传送门

台阶-Nim游戏

一、结论

如果奇数阶台阶的石子个数异或值不是零,则先手必胜。

如果奇数阶台阶的石子个数异或值是零, 则先手必败。

AcWing 892. 台阶-Nim游戏

二、策略

  • 如果对手是从奇数阶台阶拿石子

    \(a_1\) ^ \(a_3\) ^ ... ^ \(a_n=x\)

    (1) \(x\neq0\) 一定存在某种方式,使得剩余石子的异或值变成零。

    (2) \(x=0\) 不管怎么拿,剩余的石子异或值肯定不为零。

  • 如果对手是从偶数阶台阶拿石子

    我就把对手拿的个数,顺次放到下一级台阶上,比如,对手从\(4\)阶台阶拿\(2\)个石子到\(3\)阶台阶,我们就从\(3\)阶台阶,把这\(2\)个石子拿到\(2\)阶上。效果就是奇数阶台阶的石子个数没有改变。这样奇数阶台阶的异或值还是一样的,没有改变。

因此无论后手如何移动,先手总能通过操作把奇数异或为\(0\)的情况留给后手,当奇数台阶全为\(0\)时,只留下偶数台阶上有石子。

核心就是:先手总是把奇数台阶异或为\(0\)的状态留给对面,即总是将必败态交给对面。

因为偶数台阶上的石子要想移动到地面,必然需要经过偶数次移动,又因为奇数台阶全\(0\)的情况是留给后手的,因此先手总是可以将石子移动到地面,当将最后一个(堆)石子移动到地面时,后手无法操作,即后手失败。

因此如果先手时奇数台阶上的值的异或值为非\(0\),则先手必胜,反之必败!

三、代码

#include <bits/stdc++.h>

using namespace std;
int n;
int res;

int main() {
    //优化输入
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++) {
        int x;
        cin >> x;
        if (i % 2) res ^= x;
    }
    if (res) puts("Yes");
    else puts("No");
    return 0;
}

相关文章: