若干堆石子,每次可以选一堆分成相等的质数份或直接消去,没有石子失败,是否先手必胜?(蓝桥杯 2022 年第十三届决赛真题)
这份题解已很详尽,其中代码为 50% 分,现改为全分。
#include <iostream>
#include <unordered_set>
const int oxis = 1000001;
int primes[oxis], nprime;
bool notprime[oxis];
int fac[oxis];
int sg(int x)
{
if (x == 1 || x == 2)
return 1;
if (!notprime[x])
return 2;
static int cache[oxis];
if (cache[x])
return cache[x];
std::unordered_set<int> tui;
int x2 = x / (x & (-x)); // 跳过因数 2
for (int k = fac[x2]; x2 > 1; x2 /= k, k = fac[x2])
tui.insert(sg(x / k));
for (int i = 1;; ++i)
if (tui.count(i) == 0)
return cache[x] = i;
}
int main()
{
int t;
std::cin >> t;
for (int i = 2; i < oxis; ++i) {
if (!notprime[i]) {
primes[nprime++] = i;
fac[i] = i;
}
for (int j = 0, now; j < nprime && (now = i * primes[j]) < oxis; ++j) {
notprime[now] = true;
fac[now] = primes[j];
if (i % primes[j] == 0)
break;
}
}
while (t--) {
int n, ans = 0;
std::cin >> n;
while (n--) {
int ni;
std::cin >> ni;
ans ^= sg(ni);
}
std::cout << !!ans << std::endl;
}
}