魔法球(博弈论)

4827: 魔法球

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 15  Solved: 12
[Submit][Status][Web Board]

Description

Freda和rainbow是超自然之界学校(Preternatural Kingdom University,简称PKU)魔法学院的学生。为了展示新学的魔法,Ta们决定进行一场对弈~~~
起初Freda面前有n堆魔法珠,其中第i堆有ai颗。Freda和rainbow可以轮流进行以下操作:
1.选择n堆中魔法珠数量大于1的任意一堆。记该堆魔法珠的数量为p,p有b1、b2……bm这m个小于p的约数。
2.施展魔法把这一堆魔法珠变成m堆,每堆各有b1、b2……bm颗魔法珠。
3.选择这m堆中的一堆魔法珠,施展魔法令其消失。
注意一次操作过后,魔法珠的堆数会增加m-2,各堆中魔法珠数量的总和可能会发生变化。
当轮到某人操作时,如果每堆中魔法珠的数量均为1,那么ta就输了。
Freda和rainbow都采取最好的策略,从Freda开始。请你预测一下,谁能获胜呢?

Input

本题仅有一个测试点,包含多组数据,以EOF结尾。
每组数据的第一行包含一个整数n。
第二行包含n个整数ai。

Output

对于每组数据,在两人均采取最佳策略的前提下,若Freda能获胜,输出freda;若Rainbow能获胜,输出rainbow。

Sample Input

3
2 2 2
3
1 3 5

Sample Output

freda
rainbow

HINT

把每个输入当做一个有向图游戏,求最后XOR和即可

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=10000+10;

int f[maxn],v[maxn],num,ans,a[maxn];

int SG(int x){
    if(f[x]!=-1) return f[x];
    int now=num++;
    int p=0,i;
    for (i=1;i*i<=x;i++){
        if(x%i==0){
            if(i<x) p^=SG(i);
            if(x/i>1&&x/i<x&&i*i!=x) p^=SG(x/i);
        }
    }
    for (i=1;i*i<=x;i++){
        if(x%i==0){
            if(i<x) v[p^f[i]]=now;
            if(x/i>1&&x/i<x&&i*i!=x) v[p^f[(x/i)]]=now;
        }
    }
    for (i=0;v[i]==now;i++);
    return f[x]=i;
}

int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        memset(f,-1,sizeof(f));
        f[1]=0;
        ans=0;
        for (int i=1;i<=n;i++) scanf("%d",&a[i]),ans^=SG(a[i]);
        if(ans) printf("freda
");
        else printf("rainbow
");
    }
return 0;
}
原文地址:https://www.cnblogs.com/lmjer/p/9321967.html