[ARC155D] Avoid Coprime Game 题解

Description

非负整数 x,yx,y 的最大公约数记为 gcd(x,y)\gcd(x,y),规定 gcd(x,0)=gcd(0,x)=x\gcd(x,0)=\gcd(0,x)=x

黑板上写了 NN 个整数 A1,A2,...,ANA_1,A_2,...,A_N,这 NN 个数的最大公约数是 11。Takahashi 和 Aoki 在玩游戏,有一个变量 GG 初值为 00,他们轮流进行以下操作:

从黑板上选择一个数 aa,必须满足 gcd(a,G)1\gcd(a,G)\ne 1,从黑板上擦掉这个数,并将 GG 的值改为 gcd(a,G)\gcd(a,G)

Takahashi 先手,谁无法操作就输了,两人都采取最优策略。

请你对于 i=1,2,..,Ni=1,2,..,N 分别判断,假如第一步 Takahashi 选择的数是 AiA_i,最后谁会获胜。

  • $ 2\ \leq\ N\ \leq\ 2\ \times\ 10^5 $
  • $ 2\ \leq\ A_i\ \leq\ 2\ \times\ 10^5 $

Code

考虑对于必胜必败态进行 dp,不妨设当前 gcd 为 GG,注意到删数很难用状态表示,但是发现删掉的数一定是当前 GG 的倍数,而其他 GG 的倍数与 GG 的 gcd 还是 GG,并且不是 GG 的倍数的数一定没被删。

所以只要记录 GG 和当前轮数即可刻画这个状态,显然过不了。


先考虑每次 GG 一定会变小的情况,设 fif_i 表示 G=iG=i 是否必胜/必败,cnticnt_i 表示 ii 的倍数的个数。

那么枚举一个 jj 使得 x,gcd(i,x)=j\exists x,gcd(i,x)=j,如果 fjf_j 为必败,则 fif_i 必胜。如果所有 jj 全必胜,则 fif_i 必败。

但是这题 GG 不一定会变小,考虑什么情况下 GG 不会变小。

注意到如果存在一个 fj(j<i)f_j(j<i) 满足其是必败态,则当前操作一定最优。所以 GG 不变小当且仅当所有转移到的 fjf_j 都必胜,则两人一定不停操作直到必须变小,即操作到 cnticnt_i 轮的人会必胜。

所以只要记录一维状态表示当前操作了奇数/偶数轮,fi,0/1f_{i,0/1} 表示当前 G=iG=i,在这之前操作了偶数/奇数轮。

然后同样进行 dp,如果后继状态全必胜,则 fi,1(cntimod2)f_{i,1-(cnt_i\bmod 2)} 必胜。

时间复杂度:O(Vlog2V+N)O(V\log^2 V+N)

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
43
44
45
46
47
48
49
50
51
52
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e5 + 5;

int n;
int a[kMaxN], cnt[kMaxN], tmp[kMaxN];
bool f[kMaxN][2];
std::vector<int> d[kMaxN];

void dickdreamer() {
std::cin >> n;
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
++cnt[a[i]];
}
for (int i = 2; i <= 2e5; ++i) {
d[i].emplace_back(i);
for (int j = 2 * i; j <= 2e5; j += i)
cnt[i] += cnt[j], d[j].emplace_back(i);
}
for (int i = 2; i <= 2e5; ++i) {
bool fl = 0;
for (auto j : d[i]) tmp[j] = cnt[j];
for (int j = (int)d[i].size() - 1; ~j; --j) {
int x = d[i][j];
if (x != i && tmp[x]) {
if (!f[x][0]) f[i][1] = 1, fl = 1;
if (!f[x][1]) f[i][0] = 1, fl = 1;
}
for (auto k : d[x]) tmp[k] -= tmp[x];
}
if (!fl) f[i][~cnt[i] & 1] = 1;
}
for (int i = 1; i <= n; ++i) {
std::cout << (f[a[i]][1] ? "Aoki\n" : "Takahashi\n");
}
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
// std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

[ARC155D] Avoid Coprime Game 题解
https://sobaliuziao.github.io/2024/02/25/post/cb0b041e.html
作者
Egg_laying_master
发布于
2024年2月25日
许可协议