[博弈论]acw235魔法珠(有向图游戏的和)

https://www.acwing.com/problem/content/description/237/

题意:

思路:
每一堆看成一个游戏,异或起来就是最终的答案。
终局,这堆的值为1,sg=0;
分堆用到因数分解,复杂度\({\sqrt{n}}\),取到所有小于x的因数,代表要分成这些堆。
按照题意要拿掉一堆,利用异或的性质枚举
先将所有的数都异或起来,之后再遍历异或每个数,每次让一个堆没掉。
求这些后继状态的mex,就是当前的sg值。

代码:

const int N = 1010;
int n,sg[N];
int dfs(int x){
    if(sg[x] != -1) return sg[x];
    if(x == 1) return sg[x] = 0;
    int vis[N],d[N];
    memset(vis,0,sizeof vis);
    int pos = 0;
    for(int i=1;i * i <= x;i++){
        if(x % i == 0){
            d[pos++] = i;
            if(x / i != i && x / i < x) d[pos++] = x / i;
        }
    }
    int tmp = 0;
    for(int i=0;i<pos;i++)
        tmp ^= dfs(d[i]);
    for(int i=0;i<pos;i++){
        if(i) tmp ^= dfs(d[i-1]);
        tmp ^= dfs(d[i]);
        vis[tmp] = 1;
    }
    for(int i=0;;i++) 
        if(!vis[i]) return sg[x] = i;
}
int main(){
    memset(sg,-1,sizeof sg);
    while(~scanf("%d",&n)){
        int res = 0;
        for(int i=0;i<n;i++){
            int x;
            scanf("%d",&x);
            res ^= dfs(x);
        }
        if(res) puts("freda");
        else puts("rainbow");
    }
    return 0;
}
posted @ 2021-07-01 23:37  Isaac233  阅读(85)  评论(0)    收藏  举报