1.题目描述:
栗酱特别喜欢玩石子游戏,就是两个人玩,有n堆石子,每堆有ai个,每次一个人可以轮流选择任意一堆,取走任意多的石子(但不能不取),谁先不能取谁输。
栗酱觉得这个游戏很有趣,知道有一天,小太阳告诉她,其实如果两个人足够聪明,游戏的结局一开始就已经注定。
栗酱是一个冰雪聪明的女孩子,她不相信,希望你演示给她看。
2.输入输出:
输入描述:
多组数据,数据第一行T表示数据组数。
每组数据第一行一个n,k表示一共有n堆石子,接下来你试图从第k堆开始取,从第二行开始,每隔一个空格一个第i堆石子的数量ai。
n≤105, ai≤109
输出描述:
输出“Yes”或“No”代表从该堆开始取是否可以必胜(如果足够聪明)。
示例:
输入:
2
3 2
1 2 3
2 1
2 1
输出:
No
Yes
3.解题思路:
题目中有说明:
小太阳哥哥说,如果想赢,就试图把每堆石子数量的异或和变为0,最终便可以获得胜利,不相信自己证一下。
因此猜测应该是否能从第k堆中取出一定石子构造异或和为0的情况。我是特判了n=1的情况。
后经过查询资料,该题模型应该为nim游戏。
nim游戏介绍:
正题
Nim 游戏的规则:有n堆石子,第i堆石子有ai 个,每次可以从某一堆中取走若干个,先后手轮流取,最后无石子可取的人负。
首先给出结论:将这n堆石子的数量异或起来(即 a1 xor a2 xor ... xor an ),假如不为0,那么先手必胜,否则先手必败。
由于这东西的证明需要用到二进制,所以下面的证明都在二进制意义下讨论。
证明
首先要知道两个定义:
必胜态:双方足够聪明的情况下,在该状态时拥有操作权者必胜
必败态:双方足够聪明的情况下,在该状态时拥有操作权者必败
以及一些基础知识:如果一个状态能转移到任意一个必败态,那么该状态就是必胜态,如果不能,就是必败态。
在Nim游戏中,异或和不为0就是必胜态,否则是必败态。
先考虑必胜态怎么必胜:
假设他们异或起来为 k (k≠0) 且k的最高位为第p位,那么至少存在一个ai,满足 ai的第p位是1,那么我们只需要让ai异或上k即可,由于ai的第p位是1,所以ai异或k肯定是减少了。
异或完后,所有石子的异或和就变成了0,也就是必败态,由于能转移到必败态,所以一开始的状态为必胜态。
再考虑必败态为什么必败:
其实这个就简单很多了……由于此时异或和为0,不管怎么拿,拿完之后肯定不为 0,也就是说,这个状态只能转移到必胜态,那么这个状态就是必败态了。
3.代码:
#include<iostream>
using namespace std;
typedef long long ll;
ll num[100005];
int main(){
int t;
cin >> t;
while( t-- ){
long long int n,k;
long long int mid;
cin >> n >> k;
for(int i=0 ; i < n; i++ ){
scanf("%lld",&num[i]);
}
mid=num[0];
for(int i=1;i < n ; i++ ){
mid=mid^num[i];
}
mid=mid^num[k-1];
if(n==1)
cout<<"Yes"<<endl;
else{
if(num[k-1]>mid)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
}
}
return 0;
}