链接:https://www.nowcoder.net/acm/contest/75/F
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
共有N堆石子,已知每堆中石子的数量,两个人轮流取石子,每次只能选择N堆石子中的一堆取一定数量的石子(最少取一个),取过子之后,还可以将该堆石子中剩余的石子随意选取几个放到其它的任意一堆或几堆上。等哪个人无法取子时就表示此人输掉了游戏。注意:一堆石子没有子之后,就不能再往此处放石子了。
假设每次都是小牛先取石子,并且游戏双方都绝对聪明,现在给你石子的堆数、每堆石子的数量,请判断出小牛能否获胜。
输入描述:
可能有多组测试数据(测试数据组数不超过1000)
每组测试数据的第一行是一个整数,表示N(1<=N<=10)
第二行是N个整数分别表示该堆石子中石子的数量。(每堆石子数目不超过100)
当输入的N为0时,表示输入结束
输出描述:
对于每组测试数据,输出Win表示小牛可以获胜,输出Lose表示小牛必然会败。
示例1
输入
3 2 1 3 2 1 1 0
输出
Win Lose
备注:
提示:
例如:如果最开始有4堆石子,石子个数分别为3 1 4 2,而小牛想决定要先拿走第三堆石子中的两个石子(石子堆状态变为3 1 2 2),然后他可以使石子堆达到的状态有以下几种:
3 1 2 2(不再移动石子)
4 1 1 2(移动到第一堆一个)
3 2 1 2(移动到第二堆一个)
3 1 1 3(移动到第四堆一个)
5 1 0 2(全部移动到第一堆)
3 3 0 2(全部移动到第二堆)
3 1 0 4(全部移动到最后)
分析:参看大佬博客:https://www.cnblogs.com/jiangjun/archive/2012/11/01/2749937.html
特殊K堆石子的xor规则:
S= n1 xor n2......xor nk 判定规则:如果S=0, 则是P局面(败), S>0则是N局面(胜) 证明这个规则是合理的: 1) 终结局面, S= 0 xor 0....xor 0 =0, 判定是P局面 2) 如果有一个N局面,则S = k > 0, 假设k的二进制1最高位是第h位, 必然某个ni的第h位为1,(否则大家都为0,不可能异或出k). 那么玩家可以让ni变成 ni'=ni xor k,(ni'是变小了)。那么一个局面的S'=n1... (ni xor k)... nk 。
(ni和k异或后变小则可以是ni,变大的不是)=(n1....nk) xor k = k xor k =0. 这说明N局面后面一定跟着一个P局面 3)如果有一个P局面,则 S=n1..xor..nk =0, 操作ni变成ni' 则S' 一定不是0. 因此P局面后面的全是N局面。
用的是尼姆博弈的一个定理:
只要是存在奇数个相同的堆数,那就是必胜态。
#include<iostream> #include <cstdio> #include <cstring> using namespace std; int a[110]; //a数组用来统计每个堆数出现的次数。 int ok(int *a)//判断是否是奇异局势,只要存在一个奇数的堆数,即可判定是非奇异堆数(必胜态)。 { for(int i=0;i<110;i++) if(a[i]&1) return 1; return 0; } int main() { int n,i,m; while(~scanf("%d",&n),n) { memset(a,0,sizeof(a)); for(i=0;i<n;i++) { scanf("%d",&m); a[m]++; } printf("%s ",ok(a)?"Win":"Lose"); } return 0; }