Description
小 A 是一个名副其实的狂热的回合制游戏玩家。在获得了许多回合制游戏的世界级奖项之后,小 A 有一天突然想起了他小时候在江南玩过的一个回合制游戏。
游戏的规则是这样的,首先给定一个数
F
F
,然后游戏系统会产生 组游戏。每一组游戏包含
N
N
堆石子,小 和他的对手轮流操作。每次操作时,操作者先选定一个不小于
2
2
的正整数 (
M
M
是操作者自行选定的,而且每次操作时可不一样),然后将任意一堆数量不小于 的石子分成
M
M
堆,并且满足这 堆石子中石子数最多的一堆至多比石子数最少的一堆多
1
1
(即分的尽量平均,事实上按照这样的分石子万法,选定 和一堆石子后,它分出来的状态是固定的)。当一个玩家不能操作的时候,也就是当每一堆石子的数量都严格小于
F
F
时,他就输掉。(补充:先手从 堆石子中选择一堆数量不小于
F
F
的石子分成 堆后,此时共有
N+M−1
N
+
M
−
1
堆石子,接下来小 A 从这
N+M−1
N
+
M
−
1
堆石子中选择一堆数量不小于
F
F
的石子,依此类推)
小 A 从小就是个有风度的男生,他邀请他的对手作为先手。小 A 现在想要知道,面对给定的一组游戏,而且他的对手也和他一样聪明绝顶的话,究竟谁能够获得胜利?
Input
输入第一行包含两个正整数 和
F
F
,分别表示游戏组数与给定的数。
接下来 行,每行第一个数
N
N
表示该组游戏初始状态下有多少堆石子。之后 个正整数,表示这
N
N
堆石子分别有多少个。
Output
输出一行,包含 个用空格隔开的 0 0 或 的数,其中 0 0 代表此时小 A (后手)会胜利,而 代表小 A 的对手(先手)会胜利。
Sample Input
4 3
1 1
1 2
1 3
1 5
Sample Output
0 0 1 1
HINT
对于 100% 的数据,
T<100,N<100,F<100000
T
<
100
,
N
<
100
,
F
<
100000
,每堆石子数量
<100000
<
100000
<script type="math/tex" id="MathJax-Element-626"><100000</script> 。
以上所有数均为正整数。
Solution
发现初始的
N
N
堆石子分别都对应了一个独立的游戏,因此只需要把这 堆分开,计算它们的
SG
S
G
值后异或起来即可。
在读入
T
T
组游戏之前先进行一个预处理 DP :
表示当前还剩下
i
i
个石子的 值。
边界:当
0≤i<F
0
≤
i
<
F
时,
SG[i]=0
S
G
[
i
]
=
0
。
转移:
其中 W(x,y) W ( x , y ) 的定义为:如果 y y 是奇数则 ,否则 W(x,y)=0 W ( x , y ) = 0 。
暴力转移是平方的,显然 TLE 。
但是可以发现 ⌊ij⌋ ⌊ i j ⌋ 的取值只有 i√ i 种,可以考虑枚举 ⌊ij⌋ ⌊ i j ⌋ 的取值来计算。
假设现在枚举到了 ⌊ij⌋=k ⌊ i j ⌋ = k ,那么这时候 SG[k] S G [ k ] 和 SG[k+1] S G [ k + 1 ] 的值就能快速得到了。但我们还需要知道 imodj i mod j 和 j−imodj j − i mod j 的奇偶性。
分 j j 为奇数和偶数两种情况处理,这样知道了 的奇偶性也就知道了 j−imodj j − i mod j 的奇偶性。
设当 j∈[l,r] j ∈ [ l , r ] 时, ⌊ij⌋=k ⌊ i j ⌋ = k 。
当 j j 为偶数(需判断 内是否有偶数)时比较显然,如果 i i 为偶数那么 也为偶数,否则为奇数。
当 j j 为奇数(需判断 内是否有奇数)时,如果 i−任意奇数×k i − 任 意 奇 数 × k 得到偶数那么 imodj i mod j 也为偶数,否则为奇数。
于是,就可以在根号的复杂度内完成一次转移了。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e5 + 5, Z = 87;
int n, T, F, sg[N], tmp[Z];
void orzcyxdalao() {
int i, j; For (i, F, 100000) {
memset(tmp, 0, sizeof(tmp)); for (j = 2; j <= i;) {
int nxt = i / (i / j), p1 = sg[i / j], p2 = sg[i / j + 1], k = i / j;
if (!(j & 1) || j < nxt) tmp[i & 1 ? p1 ^ p2 : 0] = 1;
if ((j & 1) || j < nxt)
tmp[i - (j & 1 ? j : j + 1) * k & 1 ? p2 : p1] = 1;
j = nxt + 1;
}
For (j, 0, 2147483647) if (!tmp[j]) {sg[i] = j; break;}
}
}
int main() {
int i; T = read(); F = read(); orzcyxdalao();
while (T--) {
int ans = 0; n = read(); For (i, 1, n) ans ^= sg[read()];
printf(ans ? "1 " : "0 ");
}
cout << endl; return 0;
}