题目大意:
就是现在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;
}