HDU1536--S-Nim(SG函数与时间优化)

S-Nim

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

题目链接http://acm.hdu.edu.cn/showproblem.php?pid=1536

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 表示一个集合的大小 之后输入这个集合 表示对于这些堆石子中只能拿去这个集合中的元素的个数

之后输入一个m 表示接下来对于这个集合要进行m次询问 

之后m行 每行输入一个n 表示有n个堆 每堆有ni个石子 问这一行所表示的状态是赢还是输 如果赢输入W否则L


第一行就是对f数组的输入了,但有点坑的是这个输入不一定是从小到大的,所以还要排个序,不然会WA,接下来就是m个询问了,博主是个傻叉QAQ,我把SG函数放在m个询问里面了,对于每一个的n找到它最大的石子的数量然后SG跑一遍。。。果断T飞QAQ。

其实这么写没有必要,题目刚开始给你的f 数组就是让你预处理,但我们并不知道石子的数量啊?设个上限就好了,和之前HDU-1848一样,这样写就成功地降低了一大截的复杂度。然而这么写还是T了。。。。对,这一次我找了很久的BUG。。。。最后还是没找到,绝望之下将标记数组改成了bool。。。然后过了qwq也就是说清空数组的时候memset()清空bool类型的会比int之类的要快非常多。。。一个是T,一个只跑了405ms。。。。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

#define ll long long
const int mod = 1e6;
const int mac = 1e4 + 10;
const int inf = 1e8 + 10;
int f[105];
int sg[mac];
bool s[mac];
void SG(int n);

int main()
{
	int n, m, p, ss, x;
	while (scanf("%d", &ss)) {
		if (ss == 0) break;
		for (int i = 1; i <= ss; i++) {
			scanf("%d", &f[i]);
		}
		sort(f+1,f+1+ss);
		scanf("%d", &m);
		SG(ss);
		while (m--) {
			scanf("%d", &n);
			int v = 0;
			for (int i = 1; i <= n; i++) {
			    scanf("%d", &x);
				v ^= sg[x];
			}
			if (v) printf("W");
			else printf("L");
		}
		printf("\n");
	}
	return 0;
}
void SG(int n)
{
	memset(sg, 0, sizeof(sg));
	for (int i = 1; i <= mac-5; i++) {
		memset(s, false, sizeof s);
		for (int j = 1; f[j] <= i && j <= n; j++)
			s[sg[i - f[j]]] = true;
		for (int j = 0;; j++)
			if (!s[j]) { sg[i] = j; break; }
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值