HOJ2645 - WNim (SG博弈论)

Problem Description

Recently Xiao Ming is quite interested in stones. So you can imagine how happy he is when he finds a stone game called nim! If you don't know how to play nim, he is glad to teach you.

The game of nim is played as follows. There are N piles of stones containing x[0], x[1], ..., x[N-1] stones respectively. Two players take turns to move. Each move involves selecting one of the piles and removing stones from it. You may not remove stones from more than one pile in each turn, but from the pile you selected you may remove as many stones as you wish, from one stone to the whole pile. The winner is the player who removes the last stone.

But Xiao Ming doesn't like the rule of nim, so he makes some changes. Before the start of the game, he chooses some positive integers. Then two players start to play nim. During a player's turn, if there is at least one non-empty stone pile whose number of stones is a multiple of any of the integers chosen by Xiao Ming, he is allowed to remove all piles in this move and win the game immediately. Otherwise, he must follow the rule of nim stated above. The winner is still the one who removes the last stone. Xiao Ming happily and creatively calls the new game "W-Nim".

Now Xiao Gang and Xiao Hong have learned the rule of W-Nim from Xiao Ming, and they want to play it. Given a W-Nim game, Xiao Ming wants to know who will win at last, if both Xiao Hong and Xiao Gang play optimally. Xiao Hong always moves first.

 

Input

Input contains multiple test cases. The first line is an integer 1 ≤ T ≤ 20, the number of test cases. Each case begins with two integers M and N with 0 ≤ M ≤ 10 and 1 ≤ N ≤ 100. The next contains M integers p[0], p[1], ..., p[M-1] which are the integers chosen before the game by Xiao Ming. The third line contains N integers a[0], a[1], ...., a[N-1] representing stone piles with a[0], a[1], ..., a[N-1] stones respectively. You are guaranteed that 1 ≤ a[i] ≤ 109 and 2 ≤ p[i] ≤ 1000.

 

Output

For each test case, output a line which contains either "Xiao Gang" or "Xiao Hong", which is the winner of this game.

 

Sample Input

 

4
2 5
2 100
4 3 5 7 9
1 2
2
1 3
1 2
2
123456789 123456789
1 3
2
1 3 5

 

Sample Output

 

Xiao Hong
Xiao Hong
Xiao Gang
Xiao Gang

 

Hint

Sample 1: The number of stones in the first pile is a multiple of 2. So according to the rule, Xiao Hong can take all the stones in this turn and win.

Sample 2: Xiao Hong can remove two stones from the second pile.

Sample 3: Whatever action Xiao Hong makes, Xiao Gang can do the same thing on the other pile. Therefore Xiao Hong loses the game.

Sample 4: According to the rule of normal nim game, Xiao Hong should take 3 stones from the third pile to win the game. But under the rule of W-Nim, if Xiao Hong does this, the third pile will have 2 stones, which is a multiple of 2, so Xiao Gang can take all stones to win immediately. In fact, in this case Xiao Hong cannot win no matter how she moves.


题解:运用sg函数进行状态转化

假如S{2,3,4}   

sg(0)=0; sg(1)=1;sg(2)=2;

sg(5)=mex{sg[0],sg[1],sg[2]}=3;

sg(7)=mex{sg[0],sg[1],sg[2],sg[5]}=4;

所以我们不难发现sg[x]=x-y;y为1~x之间能被s集合任意一个数整除的个数

就拿12来说:

2:  2 4 6 8 10 12      ----->12/2=6个

3: 3 6 9 12               ----->12/3=4个

4:4 8 12                   ----->12/4=3个

但是这当中有重叠的要减去能被任意两个数的公倍数整除的数量,但是又要加上能被任意三个的公倍数整除的数量,所以通过这个规律我们不难发现对于偶数组成的最小公倍数我们减去它,任意奇数组成的最小公倍数的数量我们要加上它;因为s集合最大十所以我们可以通过二进制状态枚举所有类型然后依照上面计算就好了。


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
#define ps(a)     push(a)
#define clr(a,b)  memset(a,b,sizeof(a))
const int maxn=100+5;
const int minn=10+8;
int p[maxn],a[maxn];
int gcd(int a,int b)
{
    if(a<b){swap(a,b);}
    return b?gcd(b,a%b):a;
}
int lcm(int a,int b)
{
    return a*b/gcd(a,b);
}
int get_sg(int x,int m)
{
    int ans=x;
    for(int i=1;i<(1<<m);i++)
    {
        int  cnt=0;//记录次数
        int  cmm=1;//最小公倍数
        for(int j=0;j<m;j++)
        {
            if((1<<j)&i){cnt++;cmm=lcm(cmm,p[j]);}//记录最小公倍数
        }
        if(cmm>x){continue;}
        if(cnt%2)ans-=x/cmm;
        else     ans+=x/cmm;
    }
    return ans;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("data.txt","r",stdin);
    #endif
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m,n,flag=0,ret=0;
        scanf("%d%d",&m,&n);
        for(int i=0;i<m;i++)
        {
            scanf("%d",&p[i]);
        }
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            for(int j=0;j<m;j++){if(a[i]%p[j]==0){flag=1;}}
            ret^=get_sg(a[i],m);
        }
        ret+=flag;
        puts(ret ? "Xiao Hong" : "Xiao Gang");
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值