本题是道好题,虽然比较水,但是确实算是sg函数的一种应用了,首先O(n^2)的暴力求sg函数就可以拿到70分,之后我们考虑对于每一堆x,我们枚举它能分成的堆数i,那么它一定会分成n%i个n/i+1和i-n%i个n/i的,而n/i只有根号n个取值,然后就可以用通常数论的思路来枚举这根号n个取值。对于n%i和i-n%i,我们只需要知道它们的奇偶性就可以了,所以我们只需要枚举前两个(因为如果有两种奇偶性,那么前两种必定不同(差不多就是这个意思)),然后就可以O(n sqrt(n))解决了。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 100010
using namespace std;
int sg[maxn];
int T,F,n;
int get_sg(int x)
{
if (sg[x]!=-1) return sg[x];
if (x<F) return sg[x]=0;
bool vis[maxn];
memset(vis,0,sizeof(vis));
for (int i=2;i<=x;i=x/(x/i)+1)
for (int j=i;j<=min(i+1,x);j++)
{
int t=0;
if ((x%j)&1) t^=get_sg(x/j+1);
if ((j-(x%j))&1) t^=get_sg(x/j);
vis[t]=1;
}
for (int i=0;;i++) if (!vis[i]) return sg[x]=i;
}
int main()
{
scanf("%d%d",&T,&F);
memset(sg,-1,sizeof(sg));
while (T--)
{
scanf("%d",&n);
int ans=0;
for (int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
ans^=get_sg(x);
}
if (ans) printf("1"); else printf("0");
if (T) printf(" ");
}
printf("\n");
return 0;
}