魔法珠
题目
解析
这道题需要一个知识:有向图游戏,SG函数与mex运算
我们先从有向图游戏讲起:
在一个DAG中,只有一个起点,上面有一个棋子,两个玩家轮流推动棋子,不能推动判负
mex:
mex就是不属于集合S的最小非负整数,即
m
e
x
(
S
)
=
m
i
n
x
∈
N
,
x
∉
S
(
x
)
mex(S)=min_{x∈N,x∉S}(x)
mex(S)=minx∈N,x∈/S(x)
SG函数:
对于状态
x
x
x及其
k
k
k个后继状态
a
1
,
a
2
.
.
.
a
k
a_1,a_2...a_k
a1,a2...ak,定义SG函数
S
G
(
x
)
=
m
e
x
(
S
G
(
a
1
)
,
S
G
(
a
2
)
.
.
.
S
G
(
a
k
)
)
SG(x)=mex(SG(a_1),SG(a_2)...SG(a_k))
SG(x)=mex(SG(a1),SG(a2)...SG(ak))
性质:
1,最终状态SG=0
2,必胜状态SG≠0必有一个后继状态SG=0
3,必败状态SG=0必无后继状态SG=0
SG定理:
对于由
n
n
n个有向图游戏组成的组合游戏,设它们的起点分别是
s
1
,
s
2
,
.
.
.
,
s
n
s_1,s_2,...,s_n
s1,s2,...,sn,则
当且仅当
S
G
(
s
1
)
x
o
r
S
G
(
s
2
)
x
o
r
.
.
.
x
o
r
S
G
(
s
n
)
≠
0
SG(s_1)\;xor\;SG(s_2)\;xor\;...\;xor\;SG(s_n)≠0
SG(s1)xorSG(s2)xor...xorSG(sn)=0时,先手必胜
证明:
1,最终局面显然成立
2,对于任意情况,显然可以取到该数-1,不能取到原数(否则等同于没取),也就是NIM游戏
对于这道题,显然直接暴力SG即可
当然也可以打表写出SG值
code:
#include<cstdio>
#include<cstring>
using namespace std;
int n,x,sg[1010],ans;
inline int SG(int x)
{
if(sg[x]!=-1)return sg[x];
int y=0;
for(int i=1;i*i<=x;++i)if(!(x%i)){if(i!=x)y^=SG(i);if(i*i!=x&&i!=1)y^=SG(x/i);}
bool ch[1010];memset(ch,0,sizeof(ch));
for(int i=1;i*i<=x;++i)if(!(x%i)){if(i!=x)ch[SG(i)^y]=1;if(i*i!=x&&i!=1)ch[SG(x/i)^y]=1;}
while(ch[++sg[x]]);
return sg[x];
}
int main()
{
for(int i=1;i<=1000;++i)sg[i]=-1;
while(scanf("%d",&n)!=EOF)
{
ans=0;
while(n--)scanf("%d",&x),ans^=SG(x);
printf(ans?("freda\n"):("rainbow\n"));
}
return 0;
}