喵哈哈村的魔法考试 Round #6 (Div.3) E

喵哈哈村的代码传说 第五章 找规律

发布时间: 2017年3月11日 16:04   最后更新: 2017年3月11日 16:04   时间限制: 1000ms   内存限制: 128M

桌面上有n组牌,每组牌有a[i]个扑克,两个玩家轮流拿扑克,谁拿到最后一张扑克,谁就胜利了。

但是这个规矩有点奇怪:他们可以选择一堆拿任意多的扑克牌,或者选择使得某一堆扑克牌变成三堆任意大小的扑克牌。

请问如果两个人都非常机智的话,谁能获胜呢?

第一行包括数据组数T,表示测试数据组数。
接下来T组测试数据:
第一行一个n,表示有n组牌。
第二行n个数字a[i],表示每组牌的数量。

保证n<=1000000,a[i]<=1e9

第一个人胜利输出First player wins.
第二个人胜利输出Second player wins.

复制
2
2
4 4
3
1 2 4
Second player wins.
First player wins.

一看到题目,找规律?
这不简单? 然后就开始找规律...2的倍数 3的倍数 各种模?

博弈论--sg函数
sg函数定义:sg(x)=mex{y|sg(y)} y为x可以到达的子状态,mex为集合中未出现的最小整数
还有一个结论
直接说结论好了。(Bouton's Theorem)对于一个Nim游戏的局面(a1,a2,...,an),它是P-position当且仅当a1^a2^...^an=0,其中^表示异或(xor)运算。
怎么样,是不是很神奇?我看到它的时候也觉得很神奇,完全没有道理的和异或运算扯上了关系。但这个定理的证明却也不复杂,基本上就是按照两种position的证明来的。
所以对于一个由多个子游戏组成的游戏,直接 sg(i1)^sg(i2)^sg(i3)...
枚举一下发现 当sg=k*8+7 时,sg有子状态k*8+7 举个栗子...sg=7 它可以分成小游戏 1 2 4三堆牌, 从这三堆牌里面拿 sg异或和为7,所以此时sg应该为8...
找到这个规律之后...就是简单的取石子游戏了(Nim)
 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 typedef long long ll;
 5 ll n, m;
 6 int main(){
 7     cin>>n;
 8     while(n--){
 9         cin>>m; 
10         ll a, sg=0;
11         for(int i=0; i<m; i++){
12             cin>>a;
13             if(a%8==7)    a=a+1;
14             else if(a%8==0) a=a-1;
15             sg=sg^a;
16         }
17         if(sg!=0) printf("First player wins.
");
18         else printf("Second player wins.
");
19     }
20     return 0;
21 }
原文地址:https://www.cnblogs.com/ledoc/p/6558910.html