题面
题解
无论一堆石头怎么拆分,都并不能改变它是一个
Multi−SG
M
u
l
t
i
−
S
G
的事实。
既然每一组的
F
F
都是固定的,那么我们预处理所有的可能的堆,而将石子拆分成若干堆,也只需要考虑函数的值就好了。
但是这样子求
SG
S
G
值的复杂度是
O(V2)
O
(
V
2
)
的,其中
V
V
是值域,也就是。
再分析一下,将
x
x
个式子拆分成的最少的石子个数是,最多的情况是
[x/m+1]
[
x
/
m
+
1
]
,
因为
[x/m]
[
x
/
m
]
可以数论分块,而对于
SG
S
G
函数值的影响之和奇偶性相关,所以只需要考虑
[x/m],[x/m+1]
[
x
/
m
]
,
[
x
/
m
+
1
]
出现次数的奇偶性一共
4
4
中情况考虑。
个数的奇偶性只和
m
m
相关,个数的奇偶性只和
x%m
x
%
m
相关,而
x%m=x−m[x/m]
x
%
m
=
x
−
m
[
x
/
m
]
。
而
[x/m]
[
x
/
m
]
在数论分块中是定值,不需要额外考虑,那么只需要考虑
m
m
<script type="math/tex" id="MathJax-Element-1933">m</script>的奇偶性就好啦。
然而预处理的话复杂度比较爆炸,毕竟我们不一定所有的值都会被用到,那么就写一个记忆化搜索。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#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 SG[MAX],vis[MAX];
int getSG(int x)
{
if(~SG[x])return SG[x];
for(int i=2,k;i<=x;i=k+1)
{
k=x/(x/i);
for(int j=i;j<=min(i+1,k);++j)
{
int s=0;
if((x%j)&1)s^=getSG(x/j+1);
if((j-x%j)&1)s^=getSG(x/j);
vis[s]=x;
}
}
for(int i=0;;++i)if(vis[i]!=x)return SG[x]=i;
}
int main()
{
int T=read(),F=read();
memset(SG,-1,sizeof(SG));
for(int i=0;i<F;++i)SG[i]=0;
while(T--)
{
int n=read(),s=0;
while(n--)s^=getSG(read());
printf("%d ",(bool)s);
}
return 0;
}