取沙子游戏

取沙子游戏

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 的幂次相同,可以得到这个状态为必胜态。证明如下:

  1. 只要取 x = k * 2^u 就相当于 (p * 2^(m-u) - t - k, k) 的变化,属于必败态。(s 中 2 的因子更多)
  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;
}
posted @ 2026-09-08 20:01  thenrify  阅读(21)  评论(0)    收藏  举报