HDU 1535 S-Nim(SG函数)

S-Nim

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 8729    Accepted Submission(s): 3660


Problem Description

Arthur and his sister Caroll have been playing a game called Nim for some time now. Nim is played as follows:


  The starting position has a number of heaps, all containing some, not necessarily equal, number of beads.

  The players take turns chosing a heap and removing a positive number of beads from it.

  The first player not able to make a move, loses.


Arthur and Caroll really enjoyed playing this simple game until they recently learned an easy way to always be able to find the best move:


  Xor the number of beads in the heaps in the current position (i.e. if we have 2, 4 and 7 the xor-sum will be 1 as 2 xor 4 xor 7 = 1).

  If the xor-sum is 0, too bad, you will lose.

  Otherwise, move such that the xor-sum becomes 0. This is always possible.


It is quite easy to convince oneself that this works. Consider these facts:

  The player that takes the last bead wins.

  After the winning player's last move the xor-sum will be 0.

  The xor-sum will change after every move.


Which means that if you make sure that the xor-sum always is 0 when you have made your move, your opponent will never be able to win, and, thus, you will win. 

Understandibly it is no fun to play a game when both players know how to play perfectly (ignorance is bliss). Fourtunately, Arthur and Caroll soon came up with a similar game, S-Nim, that seemed to solve this problem. Each player is now only allowed to remove a number of beads in some predefined set S, e.g. if we have S =(2, 5) each player is only allowed to remove 2 or 5 beads. Now it is not always possible to make the xor-sum 0 and, thus, the strategy above is useless. Or is it? 

your job is to write a program that determines if a position of S-Nim is a losing or a winning position. A position is a winning position if there is at least one move to a losing position. A position is a losing position if there are no moves to a losing position. This means, as expected, that a position with no legal moves is a losing position.
 

Input

Input consists of a number of test cases. For each test case: The first line contains a number k (0 < k ≤ 100 describing the size of S, followed by k numbers si (0 < si ≤ 10000) describing S. The second line contains a number m (0 < m ≤ 100) describing the number of positions to evaluate. The next m lines each contain a number l (0 < l ≤ 100) describing the number of heaps and l numbers hi (0 ≤ hi ≤ 10000) describing the number of beads in the heaps. The last test case is followed by a 0 on a line of its own.
 

Output

For each position: If the described position is a winning position print a 'W'.If the described position is a losing position print an 'L'. Print a newline after each test case.
 

Sample Input

2 2 5 3 2 5 12 3 2 4 7 4 2 3 7 12 5 1 2 3 4 5 3 2 5 12 3 2 4 7 4 2 3 7 12 0
 

Sample Output

LWW
WWL
 

题意

首先给出k,表示有几种每次取石子个数的集合,即给出123,每次可以取1,2,3个。然后给出询问次数m。每次询问给出n堆石子,然后询问当前状态是P还是N。

分析

SG函数。两种求法,都写了一遍。耗时间差不多

code

预处理

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 
 5 using namespace std;
 6 
 7 const int N = 10000;
 8 int sg[10100],f[1010];
 9 int k,n,m;
10 bool Hash[1010];
11 
12 void get_SG() {
13     memset(sg,0,sizeof(sg));
14     for (int i=1; i<=N; ++i) {
15         memset(Hash,false,sizeof(Hash));
16         for (int j=1; j<=k&&f[j]<=i; ++j) 
17             Hash[sg[i-f[j]]] = true;
18         for (int j=0; j<=N; ++j) 
19             if (!Hash[j]) {sg[i] = j;break;}        
20     }
21 }
22 
23 int main () {
24     while (~scanf("%d",&k) && k) {
25         for (int i=1; i<=k; ++i) 
26             scanf("%d",&f[i]);
27         sort(f+1,f+k+1);
28         get_SG();
29         scanf("%d",&m);
30         for (int i=1; i<=m; ++i) {
31             scanf("%d",&n);
32             int ans = 0;
33             for (int t,j=1; j<=n; ++j) {
34                 scanf("%d",&t);
35                 ans ^= sg[t];
36             }
37             if (ans == 0) printf("L");
38             else printf("W");
39         }
40         puts("");
41     }
42     return 0;
43 }
View Code

dfs记忆化搜索

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 
 6 int sg[10100],f[1010];
 7 int k,n,m;
 8 
 9 int get_SG(int x) {
10     if (sg[x] != -1) return sg[x];
11     bool Hash[110]; //不能再外面开 
12     memset(Hash,false,sizeof(Hash));
13     for (int i=1; i<=k; ++i) {
14         if (f[i] > x) break;
15         get_SG(x-f[i]);
16         Hash[sg[x-f[i]]] = true;
17     }
18     for (int i=0; ; ++i) 
19         if (!Hash[i]) {sg[x] = i;break;}
20     return sg[x];
21 }
22 int main () {
23     while (~scanf("%d",&k) && k) {
24         for (int i=1; i<=k; ++i) 
25             scanf("%d",&f[i]);
26         sort(f+1,f+k+1);
27         memset(sg,-1,sizeof(sg));
28         sg[0] = 0;
29         scanf("%d",&m);
30         for (int i=1; i<=m; ++i) {
31             scanf("%d",&n);
32             int ans = 0;
33             for (int t,j=1; j<=n; ++j) {
34                 scanf("%d",&t);
35                 ans ^= get_SG(t);
36             }
37             if (ans == 0) printf("L");
38             else printf("W");
39         }
40         puts("");
41     }
42     return 0;
43 }
View Code
原文地址:https://www.cnblogs.com/mjtcn/p/8481074.html