三堆石子

题目描述:
有三堆石子,两个人轮流从其中一堆取1到任意颗石子,并约定取走所有三堆中最后一颗石子的人胜利。
现给定石子数量,问先手有没有必胜策略?
输入:
一行,三个正整数a,b,c表示石子数量,用空格隔开。

输入:
若先手必胜,输出2个整数x,y,表示先手第一步从第x堆石子取y颗,如果有多种方案致胜,输出所有方案,每行一个,按照取的石子的编号从小到大排序。
否则输出一行no。

数据范围:
分数 数据范围
10 max(a,b,c)<=10
30 max(a,b,c)<=50
30 max(a,b)<=50,c<=10000
20 max(a,b,c)<=10000
10 max(a,b,c)<2147483648

时间限制:1s

样例数据:
输入 输出
2 3 2 1 1
2 3
3 1
1 2 3 no
3 5 10 3 4
6 10 12 no
114514 1919893 1897671 no
样例解释:
第1组数据,先手可以取走3颗石子一堆的所有石子。


题解:本题目是个典型的Nim游戏。用到一个位运算:异或”^”。

            首先一旦从xor为零的状态时取走至少一颗石子,xor就会变得不等于0,再后手取一个相同的数量(为啥见coin game题解),这时xor的值又变成0了!

             所以必败态一定只能转到必胜态[惊不惊喜,意不意外]所以a1 xor a2 xor a3 xor a4 …… xor an的值如果等于零,则先手必败,因为最后一个石子是后手拿走的。

            如果其值不等于0.则是必胜!好了,现在yes 和 no的问题解决了,再来看yes时的输出方案,如果a>(b^c),a只有在与b xor c相等时,才会a xor b xor c = 0 所以在第一堆当中取走a-(b^c),这时a=a-(a-(b^c))可以得出                  a=b^c。因为第一次取完后,xor的值就等于0了。此时后手就成了“先手”,而xor等于0时“先手”必输,所以后手必输,不就是先手必胜吗!b和c的做法与a相同。得证!

 

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int a,b,c;
int main()
{
    freopen("tristone.in","r",stdin);
    freopen("tristone.out","w",stdout);
    cin>>a>>b>>c;
    if((a^b^c)==0) cout<<"no";
    else
    {
        if(a>(b^c)) cout<<"1 "<<a-(b^c)<<endl;
        if(b>(a^c)) cout<<"2 "<<b-(a^c)<<endl;
        if(c>(a^b)) cout<<"3 "<<c-(a^b)<<endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wuhu-JJJ/p/11149998.html