P9473 [yLOI2022] 西施江南

· · 题解

Analysis

考虑唯一分解定理,对 n 个数 a_1, a_2, a_3, \dots a_n,设 a_i = \prod p_j^{c_{i,j}}。则其 \gcd = \prod p_j ^{\min\limits_i c_{i,j}}\mathrm{lcm} = \prod p_j^{\max\limits_i c_{i,j}}\gcd \times \mathrm{lcm} = \prod p_j^{\min\limits_i c_{i,j} + \max\limits_i c_{i,j}}。又 \prod a_i = \prod p_j^{\sum_{i= 1}^n c_{i,j}}。于是回答为是的充要条件是 \sum_{i = 1}^n c_{i,j} = \min c_{i,j} + \max c_{i,j}。易见 \max c_{i,j} 一定是左边的一项,所以需要 \min c_{i,j} 等于左边剩下的项。

讨论一下:

  1. n > 2 时,假设 \min c_{i,j} = k。不妨假设 \min c_{ i,j} = c_{1,j} \leq c_{2, j} \leq c_{3, j} \leq \dots \leq c_{n,j} = \max c_{i,j}。想要让这些项目的和等于 \min c_{i,j} + \max c_{i,j},则 c_{2,j} = c_{3, j} = c_{4, j} = \dots = c_{n - 1,j} = 0。又 c_{2,j} \geq \min c_{i,j},于是 \min c_{i,j} = 0
    因此,此时每个质数只能作为一个数字的因子。换句话说,数字是两两互质的。

综上,当 n = 2 时,总是回答是,否则如果给定的数字两两互质,回答是,否则回答否。

子任务 1

## 子任务 2 $n \leq 5$ 时,可以暴力计算这些数字的积,检查他们的 gcd 和 lcm 的关系。 ## 子任务 3 $n \leq 1000$ 时,可以暴力枚举每一对数,求他们的 gcd,看它们是不是两两互质。时间复杂度 $O(n^2 \log a)$。 ## 子任务 4 回到『每个质数只能作为一个数的因子』这个表述上,可以据此检查所有数是否两两互质。方法是:对每个数 $O(\sqrt a_i)$ 地分解质因子。用一个数组记录每个质因子是否在之前的数中出现过。如果某个质因子之前出现过,直接返回否即可。时间复杂度 $O(n \sqrt a_i)$。 ## 子任务 5 可以在线性筛的同时筛出每个数的最小质因子,具体的方法见 [B3716](https://www.luogu.com.cn/problem/B3716)。 这样就可以 $O(\log a_i)$ 筛出每个数的质因子,然后按子任务 $4$ 的做法判断即可。时间复杂度 $O(T n \log a_i)$。 ## Code ```cpp #include <vector> #include <iostream> const int maxn = 100000005; int T; std::vector<int> prm, pre; // pre is the min-factor array. bool np[maxn]; bool oc[maxn]; void getPrime(const int N = 100000000) { pre.resize(N + 1); for (int i = 2; i <= N; ++i) { if (!np[i]) { prm.push_back(i); pre[i] = i; } for (auto p : prm) if (i * p <= N) { int k = i * p; np[k] = true; pre[k] = p; if (i % p == 0) break; } else break; } } int main() { getPrime(); std::ios::sync_with_stdio(false); std::cin.tie(nullptr); for (std::cin >> T; T; --T) { int n; for (auto i : prm) oc[i] = false; std::cin >> n; std::vector<int> a(n); for (auto &i : a) std::cin >> i; if (n == 2) { std::cout << "Yes\n"; } else { bool ans = true; for (auto i : a) { std::vector<int> tmp; while (i != 1) { tmp.push_back(pre[i]); i /= pre[i]; } for (auto j : tmp) if (oc[j]) { ans = false; } for (auto j : tmp) { oc[j] = true; } } std::cout << (ans ? "Yes" : "No") << std::endl; } } } ```