A - Bitwise OR Game

解题思路比较好猜,有价值的点在于如何证明

首先考虑只有两个元素 a,ba,b 的情况. 考虑其二进制,如果存在 ai,bia_i,b_i 均为 11 那么先手必胜;否则如果每一个 ai,bia_i,b_i 都最多只有一个 11,那么后手必胜. 推广后可以猜测:如果所有位置上,要么是 0011,要么有奇数个 11,就是后手必胜;否则就是先手必胜.

所以考虑 Nim Game 的条件怎么转化:上述的条件其实可以转化成 XORi ai=ORi ai\text{XOR}_i\ a_i=\text{OR}_i\ a_i

简短证明

待补……

AC Code
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
#include <bits/stdc++.h>
constexpr int N = 2e5 + 10;

int n, a[N];

void run() {
std::cin >> n;
for (int i = 1; i <= n; i++) std::cin >> a[i];

int odd = 0;
auto get = [](int v, int i) { return v >> i & 1; };

int tot = 0;
for (int b = 0; b <= 60; b++) {
int cnt = 0, mk = 0;
for (int i = 1; i <= n; i++) {
cnt += get(a[i], b);

if (get(a[i], b) && !mk) {
tot++;
mk = 1;
}
}
if (cnt % 2 == 1) odd++;
}

if (odd == tot) std::cout << "Bob\n";
else std::cout << "Alice\n";
}

int main() {
std::cin.tie(0)->sync_with_stdio(0), std::cout.tie(0);
int t;
std::cin >> t;
while (t--) run();
}

B - Sum of Mod

唉其实也猜得八九不离十了,但是下界和一个关键发现没有推出来,导致没有推出可以二分的性质

我们令 di=ai+1modaid_i=a_{i+1}\mod a_i,既然是 mod\mod{} 那么 ai>dia_i\gt d_i. 我们还要猜的一个点是最优情况下 ai+1=ai+dia_{i+1}=a_i+d_i.

证明待补(

所以有了这两点后,我们可以推出 aia_{i} 的范围:

ai+1=ai+di<ai+ai=2aiai+12+1aiai+1 a_{i+1}=a_i+d_i\lt a_i+a_i=2a_i\\ \Big\lfloor\frac{a_{i+1}}{2}\Big\rfloor+1\le a_i\le a_{i+1}

在固定 ana_n 的情况下,我们可以证明,ai=ai+12+1a_i=\lfloor\frac{a_{i+1}}{2}\rfloor+1 总是可以让 Sum of Mod 取到最大,并且这个 Sum of Mod 随着 ana_n 变大而变大.

证明待补(

于是就出现了可以二分的性质:我们固定 ana_n 后,计算出 aia_{i} 序列,判断 Sum of Mod 是否 k\ge k,是的话,我们把右侧的范围收缩掉;否则把左侧范围给收缩掉.

时间复杂度 O(nlogn)O(n\log n).

AC Code
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
#include <bits/stdc++.h>
using ll = long long;
constexpr int N = 2e5 + 10;
constexpr ll V = 1e9;

ll n, a[N], k;

bool check(ll c) {
a[n] = c;
ll sum = 0;
for (int i = n - 1; i >= 1; i--) {
a[i] = a[i + 1] / 2 + 1;
sum += a[i + 1] - a[i];
}
return sum >= k;
}

void run() {
std::cin >> n >> k;
ll l = 0, r = V + 1;
while (l + 1 < r) {
ll mid = l + ((r - l) >> 1);
(check(mid) ? r : l) = mid;
}

a[n] = r;
ll tmpk = k;
for (int i = n - 1; i >= 1; i--) {
ll rest = std::min(tmpk, a[i + 1] - (a[i + 1] / 2 + 1));
a[i] = a[i + 1] - rest;
tmpk -= rest;
}

for (int i = 1; i <= n; i++) std::cout << a[i] << " \n"[i == n];
}

int main() {
std::cin.tie(0)->sync_with_stdio(0), std::cout.tie(0);
int t = 10;
std::cin >> t;
while (t--) run();
}

C - Mod of XOR

思路很巧妙的分类讨论. 我一直在分类讨论 C,XC,X 但应该直接从 nn 分类讨论

假设 CC 的最高位为 kk,即 2kC<2k+12^k\le C\lt 2^{k+1}.

  1. 如果 2kn<2k+12^k\le n\lt 2^{k+1} 且有解
    那么因为最高位的 kk 被异或掉了,此时 nC<nn\oplus C\lt n,故 nCmodn=nCn\oplus C \mod n=n\oplus C,所以 X=nCX=n\oplus C. 即 n=CXn=C\oplus X.
  2. 如果 n<2kn\lt 2^k 且有解
    那么