CF2200E题解
传送门:https://codeforces.com/contest/2200/problem/E
博弈论,先找必赢或者必输局面。找到Alice的必赢局面显然比较简单,当存在两个顺序颠倒的素数就是Alice的必赢局面。由于Alice先手可以先行构造这样的局面。首先特判掉一开始就单调不减的情况。
-
如果存在一个数 \(num\),有两个不同素因子 \(p\) 和 \(q\),其中 \(p<q\)。我们可以把当前的数替换成 \(num/p, p\)。这样我们保证了 \(p\) 出现在比他大的素因子后面,而前面一个数永远存在 \(q\) 这个因子使得序列无法单调不减。Alice胜。
-
如果所有数都只有一个素因子时,我们只需要判断这些素因子是否单调不减。
证明:如果单调不减Bob胜,反之Alice。设前一个数为 \(q^a\),后一个数为 \(p^b \ (p<q)\)。当 \(b=0\),已经有单独的 \(p\) 出现在仅由 \(q\) 这个素因子构成的数后面,序列永远无法单调减。否则,Alice在后一个数中拆一个 \(p\) 出来,也就是把这两个数拆成 \(q^a,p,p^{b-1}\)。这样也能构成 \(b=0\) 的情况,所以Alice胜。当素因子单调不减时,最后必定会拆成所有素因子构成的序列,结果也单调不减,Bob胜。
需要注意的就是:因为序列中可能包含有 \(1\) ,所以此题要认为序列中的 \(1\) 为单独的素因子。当然特判 \(1\) 是否出现在非 \(1\) 的后面也可以。
#include <bits/stdc++.h>
const int N = 5e5 + 1;
using namespace std;
int a[N];
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
bool flag = true;
for (int i = 2; i <= n; ++i) if (a[i - 1] > a[i]) flag = false;
if (flag) {
cout << "Bob" << '\n';
return;
}
int pre = 0;
bool f = false;
for (int i = 1; i <= n; ++i) {
if (a[i] == 1 && f) {
cout << "Alice" << '\n';
return;
}
if (a[i] > 1) f = true;
flag = false;
int p = 0;
for (int j = 2; j * j <= a[i]; ++j) {
if (a[i] % j == 0) {
if (flag) {
cout << "Alice" << '\n';
return;
}
flag = true, p = j;
while (a[i] % j == 0) a[i] /= j;
}
}
if (a[i] > 1) {
if (flag) {
cout << "Alice" << '\n';
return;
}
p = a[i];
}
if (p < pre) {
cout << "Alice" << '\n';
return;
}
pre = p;
}
cout << "Bob" << '\n';
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号