题面
题解
很明显是一个翻硬币游戏的变形,因此当前局面的
SG
S
G
函数值就是所有白格子单独存在的
SG
S
G
函数的异或和。
那么,对于每一个位置考虑
SG
S
G
函数。
SG(x)=mexn/xi=1{⊕ij=1SG(jx)}
S
G
(
x
)
=
m
e
x
i
=
1
n
/
x
{
⊕
j
=
1
i
S
G
(
j
x
)
}
这种东西很不好算,直接打个表,
发现对于所有
n/x
n
/
x
相同的数,他们的
SG
S
G
函数都是相同的。
那么数论分块一下就只有
O(n‾√)
O
(
n
)
个有效的的
SG
S
G
值了。
#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;
}