取沙子游戏
取沙子游戏
SG定理,lowbit
- 题目简述:有 n 粒沙子,Alice 先手,轮流取。
- 规则:第一次取:取 1 ~ min(n, k) 任意粒。之后每次取的数量必须是之前所有已取数量的最大公约数 的约数,且不能超过k,也不能超过剩余沙子数。取完最后一粒的人获胜。
- 问:在双方都绝顶聪明的情况下,Alice 能否获胜?
先定义当前状态为 (s, g),其中 s 表示剩余量,g 表示当前的限制,即前面所有数的 gcd。
- 当
s为奇数时,直接取1,就能转化成(偶数,1)的情况,是必败态,所以s为奇数时一定是必胜态。 - 接下来只需要分析
s为偶数。
当g为奇数时,肯定只存在奇数因子,状态就会转变为(s-a, a),因此s为偶数,g为奇数时败。
设 s = p * 2^m,g = q * 2^n,下一步取的数量为 t * 2^u。
情况一:u < m
下一个状态转变为 (2^u * (p * 2^(m-u) - t), t * 2^u),此时 s、g 的 2 的幂次相同,可以得到这个状态为必胜态。证明如下:
- 只要取
x = k * 2^u就相当于(p * 2^(m-u) - t - k, k)的变化,属于必败态。(s 中 2 的因子更多) - 下一步如果想要打破状态,就只能取
c * 2^v,v < u。状态转变为(2^v * (even - odd), c * 2^v),回到了之前的必胜态。
综上所述,当取u < m时,必败。
情况二:u = m
下一个状态为 (2^u * (p - t), t * 2^u),形同上述的 1.1。因此 u = m 必胜。
情况三:u > m
状态变为 (2^m(p - t * 2^(u-m)), t * 2^u),此时 s 的 2 因子少于 g,只需选择 v < m 的情况,就能把 s 中 2 的因子变得比 g 中多,变成必败态。
因此只有取 u = m 才能维持必胜态,第一步的 g 就要取到 lowbit(n),因此只要比较 lowbit(n) 和 k 就可以解决。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
int t; cin >> t;
while(t --) {
ll n, k;
cin >> n >> k;
ll lowbit = n & -n;
if(lowbit <= k) cout << "Alice\n";
else cout << "Bob\n";
}
return 0;
}

浙公网安备 33010602011771号