HDU 5794

题意:
    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 } 
我自倾杯,君且随意
原文地址:https://www.cnblogs.com/nicetomeetu/p/5743796.html