不管一堆石頭怎麼拆分,都並不能改變它是一個\(Multi-SG\)的事實。
既然每一組的\(F\)都是固定的,那麼咱們預處理全部的可能的堆,而將石子拆分紅若干堆,也只須要考慮\(SG\)函數的值就行了。
可是這樣子求\(SG\)值的複雜度是\(O(V^2)\)的,其中\(V\)是值域,也就是\(10^5\)。
再分析一下,將\(x\)個式子拆分紅的最少的石子個數是\([x/m]\),最多的狀況是\([x/m+1]\),
由於\([x/m]\)能夠數論分塊,而對於\(SG\)函數值的影響之和奇偶性相關,因此只須要考慮\([x/m],[x/m+1]\)出現次數的奇偶性一共\(4\)中狀況考慮。
\([x/m]\)個數的奇偶性只和\(m\)相關,\([x/m+1]\)個數的奇偶性只和\(x\%m\)相關,而\(x\%m=x-m[x/m]\)。
而\([x/m]\)在數論分塊中是定值,不須要額外考慮,那麼只須要考慮\(m\)的奇偶性就好啦。
然而預處理的話複雜度比較爆炸,畢竟咱們不必定全部的值都會被用到,那麼就寫一個記憶化搜索。ios
#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; }