1. 程式人生 > >Luogu3235 HNOI2014 江南樂 博弈論

Luogu3235 HNOI2014 江南樂 博弈論

col clas rac 數論 相關 貢獻 digi set https

傳送門


好火啊qwq

這道題顯然是可以直接上$SG$函數的,把每一種石子數量對應的$SG$函數搞出來然後異或。

所以我們需要考慮如何計算$SG$函數

首先一個很暴力的想法:枚舉當前分成$i$堆,假如說當前石子數量為$m$,那麽就會分出$m\ mod\ i$堆石子數量為$\lceil \frac{m}{i} \rceil$的堆和$i - (m\ mod\ i)$堆石子數量為$\lfloor \frac{m}{i} \rfloor$的堆。

然後我們知道:$ \lfloor \frac{m}{i} \rfloor $只會有$2 \sqrt{m}$個取值(數論分塊),所以我們可以通過數論分塊枚舉$\lfloor \frac{m}{i} \rfloor$

的值從而降低我們需要求的狀態的數量

然後我們只需要考慮兩種數量的石子的貢獻了。因為$SG$函數的求法是異或,所以$SG_{\lceil \frac{m}{i} \rceil}$與$SG_{\lfloor \frac{m}{i} \rfloor}$是否產生貢獻就只與$m\ mod\ i$和$i -( m\ mod\ i)$的奇偶性相關。那麽實際上我們只需要算$i$與$i+1$的情況就可以了,因為分為$\geq i+2$的$SG$函數值必定與這兩個的其中一個相等。

 1 #include<bits/stdc++.h>
 2 //This code is written by Itst
 3
using namespace std; 4 5 inline int read(){ 6 int a = 0; 7 char c = getchar(); 8 bool f = 0; 9 while(!isdigit(c)){ 10 if(c == -) 11 f = 1; 12 c = getchar(); 13 } 14 while(isdigit(c)){ 15 a = (a << 3) + (a << 1) + (c ^ 0);
16 c = getchar(); 17 } 18 return f ? -a : a; 19 } 20 21 const int MAXN = 1e5 + 10; 22 int SG[MAXN] , mex[MAXN] , F , T , N; 23 24 void dfs(int x){ 25 if(SG[x] != -1) 26 return; 27 if(x < F) 28 return (void)(SG[x] = 0); 29 for(int i = 2 ; i <= x ; i = x / (x / i) + 1) 30 for(int j = i ; j <= i + 1 && j <= x ; ++j){ 31 if((x % j) & 1) 32 dfs(x / j + 1); 33 if((j - (x % j)) & 1) 34 dfs(x / j); 35 } 36 for(int i = 2 ; i <= x ; i = x / (x / i) + 1) 37 for(int j = i ; j <= i + 1 && j <= x ; ++j){ 38 int ans = 0; 39 if((x % j) & 1) 40 ans ^= SG[x / j + 1]; 41 if((j - (x % j)) & 1) 42 ans ^= SG[x / j]; 43 mex[ans] = x; 44 } 45 SG[x] = 0; 46 while(mex[SG[x]] == x) 47 ++SG[x]; 48 } 49 50 int main(){ 51 #ifndef ONLINE_JUDGE 52 freopen("in" , "r" , stdin); 53 //freopen("out" , "w" , stdout); 54 #endif 55 memset(SG , -1 , sizeof(SG)); 56 T = read(); 57 F = read(); 58 while(T--){ 59 int ans = 0; 60 for(N = read() ; N ; --N){ 61 int a = read(); 62 dfs(a); 63 ans ^= SG[a]; 64 } 65 printf("%d " , (bool)ans); 66 } 67 return 0; 68 }

Luogu3235 HNOI2014 江南樂 博弈論