1. 程式人生 > >bzoj 3576[Hnoi2014]江南樂 sg函數+分塊預處理

bzoj 3576[Hnoi2014]江南樂 sg函數+分塊預處理

產生 奇數 只需要 main sub AI 情況 com tdi

3576: [Hnoi2014]江南樂

Time Limit: 30 Sec Memory Limit: 512 MB
Submit: 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的石子,依此類推。

小A從小就是個有風度的男生,他邀請他的對手作為先手。小A現在想要知道,面對給定的一組遊戲,而且他的對手也和他一樣聰明絕頂的話,究竟誰能夠獲得勝利?

Input


輸入第一行包含兩個正整數T和F,分別表示遊戲組數與給定的數。
接下來T行,每行第一個數N表示該組遊戲初始狀態下有多少堆石子。之後N個正整數,表示這N堆石子分別有多少個。

Output


輸出一行,包含T個用空格隔開的0或1的數,其中0代表此時小A(後手)會勝利,而1代表小A的對手(先手)會勝利。

Sample Input

4 3
1 1
1 2
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函數+分塊預處理