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;
}