Light OJ 1296

F - Again Stone Game
Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu
Submit Status

Description

Alice and Bob are playing a stone game. Initially there are n piles of stones and each pile contains some stone. Alice stars the game and they alternate moves. In each move, a player has to select any pile and should remove at least one and no more than half stones from that pile. So, for example if a pile contains 10 stones, then a player can take at least 1 and at most 5 stones from that pile. If a pile contains 7 stones; at most 3 stones from that pile can be removed.

Both Alice and Bob play perfectly. The player who cannot make a valid move loses. Now you are given the information of the piles and the number of stones in all the piles, you have to find the player who will win if both play optimally.

Input

Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 1000). The next line contains n space separated integers ranging in [1, 109]. The ith integer in this line denotes the number of stones in the ith pile.

Output

For each case, print the case number and the name of the player who will win the game.

Sample Input

5

1

1

3

10 11 12

5

1 2 3 4 5

2

4 9

3

1 3 9

Sample Output

Case 1: Bob

Case 2: Alice

Case 3: Alice

Case 4: Bob

Case 5: Alice

题意:有n堆石子,分别有a1,a2,......,an个。两个游戏者轮流操作,每次可以选一堆,

   拿走至少一个石子,但不能拿走超过一半的石子。比如,若有3堆石子,每堆分别有

   5,1,2个,则在下一轮中,游戏者可以从第一堆中拿1个或2个,第二堆中不能拿,第三堆

   只能拿一个。谁不能拿石子,就算输。

题解:刘汝佳白皮书《算法竞赛入门经典训练指南》 p137原题。首先递推出sg函数找规律。

打印sg函数找规律:

#include <iostream>
#include <cstring>
using namespace std;
const int maxn=100;
int sg[maxn];
int vis[maxn];
int main()
{
    sg[1]=0;
    for(int i=2; i<=30; i++)
    {
        memset(vis,0,sizeof(vis));
        for(int j=1; j*2<=i; j++)
            vis[sg[i-j]]=1;
        for(int j=0;; j++)
        {
            if(!vis[j])
            {
                sg[i]=j;
                break;
            }

        }
        cout<<sg[i]<<" ";
    }
    return 0;
}
/*
运行结果:
1 0 2 1 3 0 4 2 5 1 6 3 7 0 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15
Process returned 0 (0x0)   execution time : 0.062 s
Press any key to continue.
*/

发现n为偶数时,sg(n)=n/2。

把n为偶数的值全部删除后得到的数列是0 1 0 2 1 3 0 4 2 5 1 6 3 7 ...

把n为偶数的值全部删除,发现得到的数列和原数列一样。

则当n为奇数时,sg(n)=sg(n/2),这里的n是向下取整的。

以下为AC代码:

#include <iostream>
#include <stdio.h>
using namespace std;
int sg(int n)
{
    while(n&1) n>>=1; //当n为奇数时,递归到为偶数为止。
    return n>>1;
}
int main()
{
    int i,n,t,cas=1;
    cin>>t;
    while(t--)
    {
        int ans=0,data;
        cin>>n;
        for(i=0;i<n;i++)
        {
            cin>>data;
            ans^=sg(data);
        }
        if(ans)
        printf("Case %d: Alice
",cas++);
        else
        printf("Case %d: Bob
",cas++);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Ritchie/p/5396810.html