将x个石子分成m堆=>
x%m 堆 x/m+1
m-x%m堆 x/m
出现了熟悉的x/m,于是想到分块
而x%m,m-x%m的奇偶性最多只会有两种,且处在块的第一个第二个,于是乎只要枚举i,i+1的情况即可
记忆化搜索会更快啦
然而对于每一个sg的计算要单独开一个vis数组。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 100010
using namespace std;
int sg[N];
int F;
int maxn=100000;
int get_sg(int x)
{
//printf("getsg: %d\n",x);
if (sg[x]!=-1) return sg[x];
if (x<F) return sg[x]=0;
bool vis[N];
memset(vis,0,sizeof(vis));
for (int i=2;i<=x;i++)
{
int now=x/(x/i);
int SG=0;
if ((x%i)&1) SG^=get_sg(x/i+1);
if ((i-x%i)&1) SG^=get_sg(x/i);
vis[SG]=1;
if (i==now||i==x) continue;
SG=0; i++;
if ((x%i)&1) SG^=get_sg(x/i+1);
if ((i-x%i)&1) SG^=get_sg(x/i);
vis[SG]=1;
i=now;
}
for (int i=0;;i++) if (!vis[i]) return sg[x]=i;
}
int main()
{
int tt,n,ans,x;
scanf("%d%d",&tt,&F);
memset(sg,-1,sizeof(sg));
while (tt--)
{
scanf("%d",&n);
ans=0;
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
ans^=get_sg(x);
//printf("%d sg: %d\n",x,sg[x]);
}
if (ans) ans=1;
if (tt) printf("%d ",ans); else printf("%d",ans);
}
return 0;
}