2025.02.25 CW 模拟赛 D. 博弈论

D. 博弈论

给我绕昏了.

思路

考虑什么时候会是 Draw. 可以发现若 Alice 和 Bob 手中的数相等, 那么异或和就为 0, 也就是整个序列的异或和为 0. 接下来考虑异或和不为 0 的情况.

不妨设序列异或和为 \(s\). 我们对于每一位考虑, 如果这一位上是 0, 那么在这一位上, Alice 和 Bob 即为平局 \((\)因为异或和为 0\()\); 如果这位是 1, 那么就可以决出胜负. 所以我们要考虑的位便成了 \(s\) 的最高位.

我们分 \(n\) 为奇数和偶数分别讨论:

  • \(n\) 为偶数, 先手必胜.

    因为我们有奇数个 1, 那么在偶数位 / 奇数位上一定存在奇数个 1. 同时先手又可以任意控制后手选的位的奇偶性, 所以其一定可以选到奇数个 1, 先手必胜. \((\)举个例子, 序列为 10101011, 那么在奇数位上我们有奇数个 1. 如果先手选择第 1 个位置, 那么后手就只能选择第 2 / n 个位置, 这样一来, 相当于后手一直在选偶数位, 先手一直在选奇数位, 其就必胜\()\)

  • \(n\) 为奇数.

    如果序列两端都是 0, 无论先手选哪边都会转化为「\(n\) 为偶数, 有奇数个 1」的情况, 先手必败.

    否则先手必然会取两端中的一个 1, 然后无论后手取哪个, 先手就必须跟着取, 不然就会转化为必败态.

    所以我们可以先将相同的前后缀的消掉, 然后剩下的位置必须是「相邻的奇偶数位相同」先手才有可能胜 \((\)例如 001100...\()\), 否则后手必胜.

    另外, 若 1 的个数不为 4 的倍数, 先手和后手会将数字全部取完, 由于先手每次会与后手选择相同的数, 于是先手会选奇数个 1, 再加上最开始的一个 1, 总共偶数个 1, 输了. 所以先手胜的条件还有「1 的个数是 4 的倍数」.

总时间复杂度 \(\mathcal{O}(\sum n)\).

代码
复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
#include "iostream" using namespace std; #define getbit(x) (31 - __builtin_clz(x)) constexpr int N = 1e5 + 10; int n, a[N], s, cnt; bool check(int l, int r) { for (; a[l] == a[r]; ++l, --r); for (int i = l; i <= r; i += 2) if (a[i] ^ a[i + 1]) return false; return true; } void init() { cin >> n, s = cnt = 0; for (int i = 1; i <= n; ++i) cin >> a[i], s ^= a[i]; int w = getbit(s); for (int i = 1; i <= n; ++i) a[i] = a[i] >> w & 1, cnt += a[i]; } void calculate() { if (!s) return puts("Draw"), void(); if (!(n & 1)) return puts("Alice"), void(); if (!(a[1] + a[n]) or cnt % 4 ^ 1) return puts("Bob"), void(); int f = 0; if (a[1]) f or_eq check(2, n); if (a[n]) f or_eq check(1, n - 1); puts(f ? "Alice" : "Bob"); } void solve() { cin.tie(nullptr); int T; cin >> T; while (T--) { init(); calculate(); } } int main() { solve(); return 0; }
posted @   Steven1013  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开