题目大意:
就是现在3堆石子, 每次操作从其中一堆拿走任意数量的石子, 或者从同时3堆中拿走同样数量的石子, 每次操作拿的石子数量至少是1颗
两人轮流进行操作
拿走最后一颗石子的人胜
对于给出的三堆石子的数量a, b, c <= 1e12, 判断谁会获得胜利, 如果先手胜利输出必胜的第一步, 任意一种即可
大致思路:
这个题表示看了半天觉得好像和3堆的Nim博弈没有区别就直接当Nim博弈做了...然后就AC了....
不过还是需要证明的
为了证明这和Nim博弈是一个东西, 需要证明SG值没有变化, 而证明SG值没有变化的关键就在于原本SG为0的点不能到达SG不为0的点
也就是要证明如果有 a^b^c == 0那么不存在 0 < t <= min(a, b, c)使得(a - t)^(b - t)^(c - t) == 0
这个的证明要感谢hust的zk提供的一个证明思路:考虑正整数 t 在二进制表示下的最低位的1
对于这个位置, 一个数n 减去 t , 这一位要么从0变成1要么从1变成0
而a - t, b - t, c - t由于满足a^b^c == 0那么 a, b, c中这个位的值要么是(0, 0, 0)要么是(1, 1, 0)
于是a - t, b - t, c - t就是1, 1, 1或者0, 0, 1那么异或值一定不是0
也就是说原本Nim游戏中的SG值是0的部分不会改变
那么就可以按照原本Nim游戏的必胜方式获胜了, 每次走到异或值为0的状态着胜
于是判断初始a^b^c的值即可判断谁获胜, 第一步自然是那成异或值为0的局面即可
代码如下:
Result : Accepted Memory : 4 KB Time : 60 ms
/* * Author: Gatevin * Created Time: 2015/8/14 19:08:31 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; int main() { int t; lint a, b, c; //scanf("%d", &t); cin>>t; while(t--) { //scanf("%I64d %I64d %I64d\n", &a, &b, &c); cin>>a>>b>>c; if((a^b^c) == 0) puts("2"); else { printf("1 "); if(a > (b^c)) { printf("1 %I64d\n", a - (b^c)); continue; } if(b > (a^c)) { printf("2 %I64d\n", b - (a^c)); continue; } if(c > (a^b)) { printf("3 %I64d\n", c - (a^b)); continue; } } } return 0; }