sg函数_____WNim( HOJ 2645 )

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


题意:

nim游戏:

有N堆石子,每堆石子Si已知,两个人轮流选择某堆石子至少拿一个,先拿完石子的赢。

小红和小刚两个人玩nim游戏。但是小明觉得太简单了。于是小明指定了几个大于0的整数。并修改规定,如果轮到某人拿石子的时候发现某堆石子的个数为小明所指定的其中一个整数的整倍数,那么这个人可以直接拿完所有堆。即胜利。


分析:

传统的sg函数博弈题目,难点在于找sg函数值。

我们知道如果轮到某个人拿的时候,如果他选择第i堆。他一定不能拿得使该堆剩余个数为小明所指定的其中一个整数的整倍数。因为这样对方就直接胜利了。

我们举个例子假如小明指定的数为集合S;

当S = { 3 } 时。

如果某堆个数是4,那么轮到某人拿的时候只能拿2,3,4个;

所以sg[ 4 ] = mex( sg[ 2 ] , sg[ 1 ] , sg[ 0 ] )  = mex( 2,1,0 ) = 3.

同理:

 sg[ 5 ] = mex( sg[ 4 ] , sg [ 2 ] ,sg [ 1 ] ,sg [ 0 ] ) = 4

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

我们可以看出来 sg[X]  = Y 且满足X-Y为1~X范围内满足小明所指定的其中一个整数的整倍数的个数。

例如:

S = { 2, 3 , 4 }

sg[100]  =  100 - M . M就是1~100中满足为Si整倍数的个数。

2的整倍数为50个,3的整倍数为30个。4的整倍数为25个。

但是根据容斥定理可得,要去掉 6的整倍数,12的整倍数,4的整数倍。并且加上12整数倍。

6的整倍数为16个。

所以M = 50 + 30 + 25 - 16 - 25 = 64

所以sg[100] = 36


所以只需要对于给定的S集合和tar求得M即可。


代码:


#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

typedef long long ll;
int p[11];
 long long gcd(long long a, long long b)
{
    return b == 0 ? a : gcd(b, a % b);
}
int getsg(int a,int tot)
{
    int num = 0;
    for(int i = 0 ; i < (1<<tot) ; i ++)
    {
        //产生一个tot位的二进制数.
        ll ans = 1;
        int cnt = 0;
        int flag = 0;
        for(int j = 0 ; j < tot ; j ++)
        {
            if(i & ( 1<< j ))
            {
                ans = ans*p[j]/gcd(ans,p[j]);
                ++ cnt;
            }
            if(ans > a)
            {
                flag = 1;
                break;
            }
        }
        if(flag == 1) continue;
        if(cnt%2) num -= a/ans;
        else num += a/ans;
    }
    return num;
}
int main()
{
    int n,m,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i = 0 ; i < n ; i ++)
            scanf("%d",&p[i]);
        int flag = 0;
        int ans = 0;
        for(int i = 0 ; i < m ; i ++)
        {
            int step;
            scanf("%d",&step);
            if(flag) continue;
            for(int j = 0 ; j < n ; j ++)
                if(step%p[j] == 0) flag = 1;
            ans ^= getsg(step,n);
        }
        if (flag)  puts("Xiao Hong");
         else    printf("%s\n", ans ? "Xiao Hong" : "Xiao Gang");
    }
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值