标签:个性 lib 异或 lse queue lex const bitset lang
问题转化成, 有 \(N\) 堆石子, 博弈双方每次可以选择不超过 \(M\) 堆, 每堆取不超过 \(X\) 个, 总的取石子数至少为一. 问胜利方.
对于单堆来说是一个巴什博弈, \(SG\) 值为石子数模 \(X+1\).
我们回忆 \(M=1\) 时的 \(Nim\) 博弈, 它利用了这样的性质:
设石子数为 \(a[i]\), 对于 \(x<a[i]\), 有 \(x\)^\(a[i]>0\).
设所有石子数的异或值为 \(S\), \(S=0\) 时, 后继一定是 \(S\not=0\)
\(S\not=0\) 时后继一定存在 \(S=0\).
关于第二点的证明, 是利用了改变单堆石子数时, 一定是对 \(S\) 异或一个正数. 而第三点是可以证明存在一个数, 改变它就对 \(S\) 异或了 \(S\).
考虑现在面对的 \(M>1\) 情况, 我们为了利用第一个性质仍然把石子数转成二进制. "异或"时每一位做模 \(M+1\) 的加法(后面提到的异或都是这样). 当 \(S=0\) 时, 取 \(1-M\) 堆石子就相当于对 \(S\) 进行了对应次的"异或", 结果必不为 \(0\). \(S\not=0\) 时能找到方案使得 \(S=0\), 其实就是把 \(S\) 分解成若干个合法的二进制数, 取相应数量的石子堆来实现.
#include <algorithm>
#include <bitset>
#include <cassert>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)
const double PI = acos(-1.0);
int N, M, L, R;
int sg[35], num[35];
int main() {
while (scanf("%d %d %d %d", &N, &M, &L, &R) != EOF) {
inc(i, 0, 31) num[i] = 0;
int mx = L / (2 * PI * R);
int x;
inc(i, 1, N) {
scanf("%d", &x);
sg[i] = (int)((ceil)(x / (2 * PI * R))) % (mx + 1);
int top = 0;
while (sg[i]) {
num[top++] += sg[i] & 1;
sg[i] >>= 1;
}
}
int fail = 1;
inc(i, 0, 31) if (num[i] % (M + 1)) fail = 0;
if (fail)
printf("Bob\n");
else
printf("Alice\n");
}
}
标签:个性 lib 异或 lse queue lex const bitset lang
原文地址:https://www.cnblogs.com/hs-zlq/p/13762517.html