博弈_______Stone Game II(hdu 4388 2012多校第九场)


Problem Description
  Stone Game II comes. It needs two players to play this game. There are some piles of stones on the desk at the beginning. Two players move the stones in turn. At each step of the game the player should do the following operations.
  First, choose a pile of stones. (We assume that the number of stones in this pile is n)
  Second, take some stones from this pile. Assume the number of stones left in this pile is k. The player must ensure that 0 < k < n and (k XOR n) < n, otherwise he loses.
  At last, add a new pile of size (k XOR n). Now the player can add a pile of size ((2*k) XOR n) instead of (k XOR n) (However, there is only one opportunity for each player in each game).
The first player who can't do these operations loses. Suppose two players will do their best in the game, you are asked to write a program to determine who will win the game.
 

Input
  The first line contains the number T of test cases (T<=150). The first line of each test cases contains an integer number n (n<=50), denoting the number of piles. The following n integers describe the number of stones in each pile at the beginning of the game. 
You can assume that all the number of stones in each pile will not exceed 100,000.
 

Output
  For each test case, print the case number and the answer. if the first player will win the game print "Yes"(quotes for clarity) in a single line, otherwise print "No"(quotes for clarity).
 

Sample Input
 
   
3 2 1 2 3 1 2 3 4 1 2 3 3
 

Sample Output
 
   
Case 1: No Case 2: Yes Case 3: No



题意:


最初有n堆石子,每堆石子个数已知。两人轮流执行操作,如果当某人无法执行有效操作时即输。

操作分两步:

    第一步为:选择其中一堆石子假定石子个数为a,拿走个数不为0的一些石子使得该堆石子剩余k个并且保证(0 < k < a,k^a < a),^为异或符号。

    第二步为:加入一堆新的石子,石子个数为k^a,当然你也可以使用技能使得加入的石子个数变为(2k)^a。不过每个人每局游戏只能使用一次技能。

无法执行有效操作即第一步或者第二步无法执行时。



分析:

看似这个博弈问题每个人操作太过复杂不宜分析。但是我们逐点分析就可以发现问题的本质。

先我们不忙考虑技能,那么每次操作实际上就是将某一堆个数为a的石子分成两堆k和k^a,并且(k

我们再来看:既然操作中涉及到位运算我们就来看看二进制下操作有什么规律,a---->k,k^a。可以发现分堆之后两堆个数的二进制1的个数和与原堆个数二进制1的个数奇偶性不变。而且当如果一个堆石子个数二进制只含有一个1(也就是2的i次方)时,这个堆无法被继续操作了。也就是游戏的边界。

这个时候就有点清晰了,每次分不一定二进制1的个数总数减少,但是总数是减少的,所以一直分的情况下,二进制1的个数的总数也是会变少的。

假如只有一个石堆:

一个石子个数为n(二进制下1的个数为k)的石堆,最后可以分成m堆(每堆不可再分,所以个数就是2的i次方)。一共操作了m-1次。判断这个堆先手赢还是后手赢只需要判断m-1是奇数还是偶数。奇数先手赢,偶数后手赢。因为分堆操作不会影响1个数的奇偶性,所以m和k是同奇偶的。换句话意思就是说m-1和k-1同奇偶,对于给定的一个石堆(大小为n)。m显然是很难得到的,但是k是很容易得到的,所以我们把判断m-1奇偶转化为判断k-1奇偶。k的值就是把n转化为二进制中1的个数。

这时候我们再来看使用技能会是怎样:技能可以用(2k)^a 去替换 k^a.然而发现(2k)^a ,k^a二进制下1的个数奇偶性还是不变。说明不管是不是用技能,分堆后的1的个数的奇偶性不变。

综上我们把原问题转化一下:对于原石子的a1, a2, a3……用其含1的个数代替, b1, b2, b3,……每次选择一个bi将其分解为2个大于0的数, 最先不能为者负, 这就转化成我们熟悉的模型了, 只需考虑总堆数和sum(bi)的奇偶性就可以了。

结论: 有n个数, 设cnt为所有数在二进制下1的总个数, n+cnt为奇数时,先手胜, 否则为负


代码:

#include
using namespace std;
int getone(int num)//得到一个数二进制中1的个数
{
    int cnt = 0;
    while(num)
    {
        cnt += (num&1);
        num>>=1;
    }
    return cnt;
}
int main()
{
    int t,n,k,_case = 0;
    cin >> t;
    while(t--)
    {
        cin >> n;
        printf("Case %d: ",++_case);
        k = 0;
        int step;
        for(int i = 0 ;  i < n ; i ++)
        {
             scanf("%d",&step);
             k += getone(step);
        }
        printf((k+n)&1? "Yes\n":"No\n");
    }
    return 0;
}


你可能感兴趣的:(ACM_日常,ACM_多校专题)