bzoj 3576[Hnoi2014]江南樂 sg函數+分塊預處理
3576: [Hnoi2014]江南樂
Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1929 Solved: 686
[Submit][Status][Discuss]
Description
小A是一個名副其實的狂熱的回合制遊戲玩家。在獲得了許多回合制遊戲的世界級獎項之後,小A有一天突然想起了他小時候在江南玩過的一個回合制遊戲。
遊戲的規則是這樣的,首先給定一個數F,然後遊戲系統會產生T組遊戲。每一組遊戲包含N堆石子,小A和他的對手輪流操作。每次操作時,操作者先選定一個不小於2的正整數M
(M是操作者自行選定的,而且每次操作時可不一樣),然後將任意一堆數量不小於F的石子分成M堆,並且滿足這M堆石子中石子數最多的一堆至多比石子數最少的一堆多1(即分的盡量平均,事實上按照這樣的分石子萬法,選定M和一堆石子後,它分出來的狀態是固定的)。當一個玩家不能操作的時候,也就是當每一堆石子的數量都嚴格小於F時,他就輸掉。(補充:先手從N堆石子中選擇一堆數量不小於F的石子分成M堆後,此時共有N+M-1)堆石子,接下來小A從這N+M-1堆石子中選擇一堆數量不小於F的石子,依此類推。
Input
輸入第一行包含兩個正整數T和F,分別表示遊戲組數與給定的數。
接下來T行,每行第一個數N表示該組遊戲初始狀態下有多少堆石子。之後N個正整數,表示這N堆石子分別有多少個。
Output
輸出一行,包含T個用空格隔開的0或1的數,其中0代表此時小A(後手)會勝利,而1代表小A的對手(先手)會勝利。
Sample Input
4 31 1
1 3
1 5
Sample Output
0 0 1 1
HINT
對於100%的數據,T<100,N<100,F<100000,每堆石子數量<100000。
以上所有數均為正整數。
Source
首先每一堆石子是單獨的是絕對可以肯定的,
所以預處理好所有的石子個數,
桌面處理,就是直接暴力枚舉怎麽分,這樣的話是O(n^2)
然後我們發現。比如將100分成40堆,41堆,這類都是2或者3,而且這樣的話也就是許多分成
的種類是相同的,那麽這樣總共就√n種不同的值,
但是每種的奇偶性是比較關鍵的,
100分成40堆,2的話20堆,3的話20堆,
100分成41堆,2的話23堆,3的話18堆,
100分成42堆,2的話26堆,3的話16堆。
發現什麽
我們代數來證明,當n為奇數,一定是一部分奇數,一部分偶數
因為分成的兩種的話一定是奇偶性不同的,所以只有兩者情況
分相差1堆時正好反應。
當n為偶數也是一樣的。
所以只需n分成x與x+1兩部分時,我們只需要做相鄰兩者即可,如100只需要做40和41兩者,就可以了,
100/34=2 然後調到100/2 +1去,這樣預處理復雜度是n√n
後面用sg定理就可以了。
1 #pragma GCC optimize(2) 2 #pragma G++ optimize(2) 3 #include<iostream> 4 #include<algorithm> 5 #include<cmath> 6 #include<cstdio> 7 #include<cstring> 8 9 #define N 100007 10 using namespace std; 11 inline int read() 12 { 13 int x=0,f=1;char ch=getchar(); 14 while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} 15 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} 16 return x*f; 17 } 18 19 int T,F,Tim; 20 int a[N],sg[N]; 21 int boo[N]; 22 23 void prepare() 24 { 25 for(int x=F;x<=100000;x++) 26 { 27 Tim++;int small,num,ys,now,nxt; 28 for (int i=2;i<=x;i=nxt+1)//x與x+1是一樣的 29 { 30 small=x/i,ys=x%i; 31 num=i-ys,now=0; 32 if(num&1)now^=sg[small]; 33 if(ys&1)now^=sg[small+1]; 34 boo[now]=Tim; 35 nxt=min(x/small,x); 36 if(i+1<=nxt) 37 { 38 now=0,ys=x%(i+1); 39 num=(i+1)-ys; 40 if(num&1)now^=sg[small]; 41 if(ys&1)now^=sg[small+1]; 42 boo[now]=Tim; 43 } 44 } 45 int mex=0; 46 while(boo[mex]==Tim)mex++; 47 sg[x]=mex; 48 } 49 } 50 int main() 51 { 52 memset(sg,0,sizeof(sg)); 53 T=read(),F=read(); 54 prepare(); 55 while(T--) 56 { 57 int n=read(),ans=0,x; 58 for(int i=1;i<=n;i++) 59 x=read(),ans^=sg[x]; 60 if(ans)printf("%d",1); 61 else printf("%d",0); 62 if(T)printf(" "); 63 } 64 }
bzoj 3576[Hnoi2014]江南樂 sg函數+分塊預處理