思路
每一次操作会分裂出更多的子游戏,这与 P10501 Cutting Game 十分相似,做过那道题的做这道题应该不难。
本题可以转换为一个有向图游戏。有向图游戏先手必败当且仅当初始时的 SG 值为 0。于是考虑求 SG 值。
设 sgi 为石子数量为 i 的一堆石子的 SG 值。显然有 sg1=0。对于每堆石子,它的 SG 值为其所有可能后继局面的 SG 值的 mex。对于每个局面,它的 SG 值为每堆石子的 SG 值的异或和。记忆化搜索即可。
可以提前预处理出每个数的约数以方便转移。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline ll read() {
int x = 0, f = 1;
char ch;
while (((ch = getchar()) < 48 || ch > 57)&&ch!=EOF)if (ch == '-')f = -1;
while (ch >= 48 && ch <= 57)x = x * 10 + ch - 48, ch = getchar();
return x * f;
}
const ll N=1e2+9;
ll n,a[N];
vector<ll>yue[1009];
ll sg[1009];
void init(){
memset(sg,-1,sizeof(sg));
sg[1]=0;
for(int i=1;i<=1000;i++){
for(int j=1;j*j<=i;j++){
if(i%j==0){
yue[i].push_back(j);
if(i/j!=j&&i/j!=i)yue[i].push_back(i/j);
}
}
}
}
ll SG(ll x){
if(sg[x]!=-1)return sg[x];
ll ans=0;
for(auto i:yue[x]){
ans^=SG(i);
}
set<ll>v;
for(auto i:yue[x]){
ans^=SG(i);
v.insert(ans);
ans^=SG(i);
}
sg[x]=0;
for(auto i:v){
sg[x]++;
// cout<<x<<' '<<sg[x]<<' '<<i<<endl;
if(i!=sg[x]-1){
sg[x]--;
break;
}
}
return sg[x];
}
int main(){
init();
while(n=read(),n!=0){
for(int i=1;i<=n;i++){
a[i]=read();
}
ll ans=0;
for(int i=1;i<=n;i++){
ans^=SG(a[i]);
}
puts(ans==0?"rainbow":"freda");
}
return 0;
}