题意:
n堆石子,先拿光就赢,操作分为两种:
1.任意一堆中拿走任意颗石子
2.将任意一堆分成三小堆 ( 每堆至少一颗 )
分析:
答案为每一堆的SG函数值异或和.
故先打表寻找单堆SG函数规律.
其中,若 x 可分为 三堆 a,b,c ,则 SG[x] 可转移至子状态 SG[a] ^ SG[b] ^ SG[c] (三堆SG值异或和)
打表后发现:
SG[ 8*k - 1 ] = 8*k
SG[ 8*k ] = 8*k - 1
其余 SG[x] = x;
则可直接得出答案
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1000005; 6 int T, n; 7 int main() 8 { 9 scanf("%d", &T); 10 while ( T-- ) 11 { 12 scanf("%d", &n); 13 int sg = 0; 14 for (int i = 1; i <= n; i++) 15 { 16 int x; scanf("%d", &x); 17 if (x % 8 == 0) sg ^= (x - 1) ; 18 else if ( (x + 1) % 8 == 0) sg ^= (x + 1) ; 19 else sg ^= x; 20 } 21 if(sg) puts("First player wins."); 22 else puts("Second player wins."); 23 } 24 }
1 /* 2 SG打表 3 */ 4 #include <iostream> 5 #include <cstring> 6 using namespace std; 7 int sg[105]; 8 int GetSG(int x) 9 { 10 if (sg[x] != -1) return sg[x]; 11 int vis[105]; 12 memset(vis, 0, sizeof(vis)); 13 for (int i = 0;i < x; i++) 14 vis[GetSG(i) ] = 1; 15 int a,b,c; 16 for(a = 1; a <= x; a++) 17 for(b = a; b <= x - a; b++) 18 for(c = b; c <= x - a - b; c++) 19 if(a+b+c == x) 20 vis[GetSG(a) ^ GetSG(b) ^ GetSG(c)] = 1; 21 for(int i = 0;; i++) 22 if(!vis[i]) return sg[x] = i; 23 } 24 int main() 25 { 26 memset(sg, -1, sizeof(sg)); 27 sg[0] = 0; 28 for (int i = 1; i <= 50; i++) 29 if(sg[i] == -1) GetSG(i); 30 for(int i = 0; i <= 50; i++) 31 cout<<i<<" "<<sg[i]<<endl; 32 }