题目描述
蓝桥公司给他们的员工准备了丰厚的奖金,公司主管小明并不希望发太多的奖金,他想把奖金留给智慧的人,于是他决定跟每一个员工玩一个游戏,规则如下:
- 桌面上一共有 n 堆一元钱。
- 双方轮流行动,由小明先行动,每次行动从某一堆钱中拿走若干元(至少一元钱),取走最后一元钱的人获胜。
请问员工们能拿到奖金吗?
输入描述
第一行为一个整数 T,表示测试数据数量。
每个测试用例包含俩行。第一行为一个整数 n , 第二行包括 n 个整数 a1,a2...an 表示第 i 堆有 ai 元。
保证所有测试用例的 nn 的和不超过 2×1052×105。
输出描述
如果员工能拿到奖金输出 YES , 否则输出 NO。
输入输出样例
示例
输入
3
2
1 1
1
1
3
2 2 1
输出
YES
NO
NO
Nim游戏:
简介
有n堆不同的物品,这些堆中各自物品的数量是任意的。两名玩家轮流取走堆中物品,可以选择将某一堆中任意数量的物品拿走,至少1个,至多全部拿走,但不能不拿或跨堆拿取物品。最终,拿到最后一个物品的玩家获胜。
结论
若初态为必胜态(a1^a2^a3^......^an != 0),则先手必胜;
若初态为必败态(a1^a2^a3^......^an == 0),则先手必败。


两个定理
- 必胜态的后继状态至少存在一个必败态;
- 必败态的后继状态均为必胜态。

总结
如果先手获得的是必胜态(所有堆数量异或结果!=0),根据定理1,先手可以在一个堆中取一定数量使得给到对手的初态是必败态,又根据定理2,对手不论怎么取,最终回到你手上时仍然为必胜态(如果我初状态为必胜态,则我一定可以给下一个人制造一个必败态)。
代码实现
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T=sc.nextInt();
for (int i = 0; i < T; i++) {
int n=sc.nextInt();
int num=sc.nextInt();
for (int j = 1; j < n; j++) {
num^=sc.nextInt();
}
if (num==0) System.out.println("YES");
else System.out.println("NO");
}
sc.close();
}
}