【BZOJ4035】数组游戏(博弈论)

【BZOJ4035】数组游戏(博弈论)

题面

BZOJ
洛谷

题解

很明显是一个翻硬币游戏的变形,因此当前局面的\(SG\)函数值就是所有白格子单独存在的\(SG\)函数的异或和。
那么,对于每一个位置考虑\(SG\)函数。
\(SG(x)=mex_{i=1}^{n/x}\{\oplus_{j=1}^i SG(jx) \}\)
这种东西很不好算,直接打个表,
发现对于所有\(n/x\)相同的数,他们的\(SG\)函数都是相同的。
那么数论分块一下就只有\(O(\sqrt n)\)个有效的的\(SG\)值了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
int SG1[MAX],SG2[MAX],n,Sqr,vis[MAX],tim;
int getSG(int x){return x<=Sqr?SG1[x]:SG2[n/x];}
int nt(int i){if(i==n)return n+1;return n/(n/(i+1));}
void init()
{
    Sqr=sqrt(n);SG1[1]=1;
    for(int i=2,nw;i<=n;i=nt(i))
    {
        ++tim;nw=0;vis[nw]=tim;
        for(int j=2,k;j<=i;j=k+1)
        {
            k=i/(i/j);
            vis[nw]=vis[nw^getSG(i/j)]=tim;
            if((k-j+1)&1)nw^=getSG(i/j);
        }
        for(int j=0;;++j)
            if(vis[j]!=tim)
            {
                i<=Sqr?SG1[i]=j:SG2[n/i]=j;
                break;
            }
    }
}
int main()
{
    n=read();init();
    int T=read();
    while(T--)
    {
        int m=read(),s=0;
        while(m--)s^=getSG(n/read());
        puts(s?"Yes":"No");
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/cjyyb/p/9503558.html
今日推荐