[HAOI2015] 数组游戏 - 博弈论,SG函数

有一个长度为N的数组,甲乙两人在上面进行这样一个游戏:首先,数组上有一些格子是白的,有一些是黑的。然后两人轮流进行操作。每次操作选择一个白色的格子,假设它的下标为x。接着,选择一个大小在1~n/x之间的整数k,然后将下标为x、2x、...、kx的格子都进行颜色翻转。不能操作的人输。现在甲(先手)有一些询问。每次他会给你一个数组的初始状态,你要求出对于这种初始状态他是否有必胜策略。

Solution

用暴力 SG 打个表,发现一段一段的 SG 值都是相同的,所以套个整除分块即可

#include <bits/stdc++.h>
using namespace std;

const int N = 400005;
int n,q,lim,sg[2][N],pos[N],u[N];

int SG(int x) {
    x=n/(n/x);
    if(x>lim) return sg[1][n/x];
    else return sg[0][x];
}

void presolve() {
    int cnt=0;
    for(int i=1,j;i<=n;i=j+1) {
        j=n/(n/i);
        pos[++cnt]=j;
    }
    while(cnt) {
        int x=pos[cnt], now=0, mex=1;
        u[now]=cnt;
        for(int i=x+x,j;i<=n;i=j+x) {
            j=n/(n/i)/x*x;
            u[now^SG(j)]=cnt;
            if((j-i)/x&1^1) now^=SG(j);
        }
        while(u[mex]==cnt) ++mex;
        if(x>lim) sg[1][n/x]=mex;
        else sg[0][x]=mex;
        --cnt;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>q;
    lim=sqrt(n);
    presolve();
    while(q--) {
        int m,x,ans=0;
        cin>>m;
        while(m--) {
            cin>>x;
            ans^=SG(x);
        }
        if(ans) cout<<"Yes"<<endl;
        else cout<<"No"<<endl;
    }
}

猜你喜欢

转载自www.cnblogs.com/mollnn/p/12400733.html