【ACWing】892. 台阶-Nim游戏

题目地址:

https://www.acwing.com/problem/content/894/

有个 n n n级台阶,每级台阶有若干石子,第 i i i级台阶上有 a i a_i ai个石子( i ≥ 1 i\ge 1 i1)。两个玩家轮流操作,每个玩家可以从第 i i i级台阶上拿任意多个石子放到第 i − 1 i-1 i1级台阶上,可以全拿但不能不拿。已经拿到地面上的石子不能再拿。无法操作者视为失败。问先手是否存在必胜策略。

输入格式:
第一行包含整数 n n n。第二行包含 n n n个整数,其中第 i i i个整数表示第 i i i级台阶上的石子数 a i a_i ai

输出格式:
如果先手方必胜,则输出“Yes”。否则,输出“No”。

数据范围:
1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105
1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1ai109

我们证明,当 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 ≠ 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}\ne 0 a1a3...a2k1=0时先手有必胜策略。证明如下,首先证明三个结论:
1、首先当所有台阶都没有石子时,是个必败状态。这是显然的;
2、如果 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 ≠ 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}\ne 0 a1a3...a2k1=0,先手总可以适当移动石子,使得移动完之后 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 = 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}= 0 a1a3...a2k1=0
3、如果 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 = 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}= 0 a1a3...a2k1=0,先手无论怎么移动石子,移动完之后都有 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 ≠ 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}\ne 0 a1a3...a2k1=0
两者的证明都可以参考经典Nim游戏的证明方法:https://blog.csdn.net/qq_46105170/article/details/114006771。

由于这个游戏必然停止,如果一开始 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 ≠ 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}\ne 0 a1a3...a2k1=0,那么先手总可以适当操作,使得后手永远都面对 a 1 ∧ a 3 ∧ . . . ∧ a 2 k − 1 = 0 a_1\wedge a_3\wedge ...\wedge a_{2k-1}= 0 a1a3...a2k1=0的局面,而当游戏结束的时候,必败局面 a 1 = a 2 = . . . = a n = 0 a_1=a_2=...=a_n=0 a1=a2=...=an=0必然是后手遇到的,所以先手有必胜策略。反之,后手有必胜策略。代码如下:

#include 
using namespace std;

const int N = 100010;
int a[N];

int main() {
    int n;
    cin >> n;

    int res = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        if (i & 1) res ^= a[i];
    }

    cout << (res != 0 ? "Yes" : "No") << endl;

    return 0;
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)

你可能感兴趣的:(AC,数学,游戏,算法)