原题链接
P2197
题目类型:
普
及
+
/
提
高
{\color{lightgreen} 普及+/提高}
普及+/提高
题目大意
输入
t
t
t组数据,每组数据都有
n
n
n和
n
n
n个数字,代表第
i
(
1
≤
i
≤
n
)
i(1\le i\le n)
i(1≤i≤n)组石子的数量。
让你求出用这些石子来玩
n
i
m
nim
nim游戏,你是否有必胜策略。
n
i
m
nim
nim游戏的规则如下:
两个人
a
,
b
a,b
a,b轮流在某一堆石子中取出
≥
1
\ge 1
≥1个石子,谁取到最后一个石子就赢了。
每一次取石子不一定要在同一堆。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
2
2
1 1
2
1 0
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
No
Yes
解题思路
我们可以考虑最简单的情况:对称。
如果说每一种数量的石子堆都有偶数堆,如3 1 2 1 3 2
,无论是数量为3
、2
还是1
的石子堆,都有偶数堆,那么先手必输。
为什么呢?因为只要你取多少个石子,我就取多少个石子,我就可以保证取到最后一个石子了。
如果不是对称的呢?
那我们可以把石子分成若干个拥有
2
2
2的非负整数次方个石子的石子堆,如12
可以分成8
和4
。
这样就可以判断是否对称了。
如果还不是对称的呢?
那先手只要把不对称的东西第一步全部取走,就可以留下一个对称局面,后手必输,先手必赢。
最后我们可以用^
运算来判断对称,这样,如果当前位为0
时来一个1
,这一位就变成1
,反之亦然。
然后将每一堆的石子数异或起来,如果结果为
0
0
0,先手必输,否则先手必赢。
上代码
#include<iostream>
using namespace std;
int n,a[10001];
void work()
{
cin>>n;
int x=0;
for(int i=1; i<=n; i++)
{
int y; cin>>y;
x^=y;
}
if(x==0) cout<<"No"<<endl;
else cout<<"Yes"<<endl;
return;
}
int main()
{
int t; cin>>t;
while(t--){work();}
return 0;
}
完美切题 ∼ \sim ∼