#题解Codeforces Round 1062 (Div. 4)——D. Yet Another Array Problem
D. Yet Another Array Problem,传送门<-点我
题解:D. Yet Another Array Problem
题目大意
给定长度为 \(n\) 的数组 \(a = [a_1, a_2, \dots, a_n]\)。
求满足下列条件的最小整数 \(x\)(范围在 \([2, 10^{18}]\) 内):
- 数组中至少存在一个元素 \(a_i\),使得 \(\gcd(a_i, x) = 1\)。
如果不存在这样的 \(x\),输出 \(-1\)。
核心思路
1. 为什么只需要考虑素数?
设某个合数 \(x\) 满足条件,即存在某个 \(a_i\) 使得 \(\gcd(a_i, x) = 1\)。
根据合数的性质,\(x\) 必然拥有至少一个质因数 \(p\)(且满足 \(p < x\))。
如果 \(\gcd(a_i, x) = 1\),那么 \(a_i\) 和 \(x\) 没有任何大于 \(1\) 的公因数,因此 \(p\) 也绝不可能是 \(a_i\) 的因数,即:
\[\gcd(a_i, p) = 1
\]
这意味着:任何合数解 \(x\) 能够满足条件,它的所有素因子都天然满足条件,且素因子一定严格小于该合数。
因此,合数永远不可能成为最小的满足条件的 \(x\)。最优的答案 \(x\) 必然是一个素数。
2. 答案的上界分析
题目要求找一个最小的素数 \(p\),使得 \(p\) 不是数组中所有元素的公因数(即存在至少一个 \(a_i\) 不能被 \(p\) 整除)。
- 如果某个素数 \(p\) 不满足条件,说明对于所有 \(1 \le i \le n\),都有 \(p \mid a_i\)(即 \(\gcd(a_i, p) = p > 1\))。
- 这意味着 \(p\) 是数组中所有数的公因数。
- 考虑到数据范围 \(a_i \le 10^{18}\),一个不超过 \(10^{18}\) 的正整数所能包含的不同质因数个数是非常少的。前几个质数的乘积增长极快:\[2 \times 3 \times 5 \times 7 \times 11 \times 13 \times 17 \times 19 \times 23 \times 29 \times 31 \times 37 \times 41 \times 43 \times 47 > 10^{18} \]前 \(15\) 个素数的乘积就已经突破 \(10^{18}\)。即使 \(a_i\) 取到极限值 \(10^{18}\),它最多也只能同时被大约十几个不同的质数整除。
- 哪怕数组所有数都拥有相同的这一批质因子,我们在质数表中只需要按从小到大的顺序扫描,最多尝试几十个素数就必然能找到一个不在其质因数集内的素数 \(p\)。
3. 算法设计
- 预处理小范围素数(例如线性筛预处理前 \(10^5\) 以内的素数,实际上预处理前 100 个质数就完全足够)。
- 从最小的质数 \(p = 2, 3, 5, \dots\) 开始从小到大枚举:
- 遍历数组 \(a\),如果存在某个元素 \(a_i\) 满足 \(\gcd(a_i, p) == 1\)(或者等价于 \(a_i \pmod p \ne 0\)),则当前素数 \(p\) 即为满足条件的最小值。
- 直接输出 \(p\) 并结束当前测试用例。
复杂度分析
- 时间复杂度:
- 筛法预处理:一次性完成,时间可忽略不计。
- 单组查询:每次枚举一个素数检查整个数组需要 \(\mathcal{O}(n)\),由于最多只需要检查常数个素数(\(\le 20\) 个),单组测试用例的时间复杂度实质上为 \(\mathcal{O}(n)\)。
- 总时间复杂度:\(\mathcal{O}(\sum n)\),对于 \(\sum n \le 10^5\) 的数据规模,整体运行耗时仅约 \(30\text{ ms}\),远低于 \(2.0\text{ s}\) 时限。
- 空间复杂度:存储素数表与原数组,空间复杂度为 \(\mathcal{O}(n)\)。
C++ 代码实现
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
const int MAXN = 1e5 + 5;
int prim[MAXN] = {0};
vector<int> primes;
// 预处理素数表
void sieve() {
for (int i = 2; i < MAXN; i++) {
if (!prim[i]) {
primes.push_back(i);
for (long long j = 1LL * i * i; j < MAXN; j += i) {
prim[j] = 1;
}
}
}
}
void solve() {
int n;
cin >> n;
vector<long long> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
// 从小到大枚举质数
for (int p : primes) {
for (int i = 0; i < n; i++) {
// 只要存在一个 a[i] 不能被 p 整除,gcd(a[i], p) 就必定为 1
if (std::gcd(a[i], (long long)p) == 1) {
cout << p << "\n";
return;
}
}
}
}
int main() {
// 快速 IO
ios::sync_with_stdio(false);
cin.tie(nullptr);
sieve();
int t;
if (cin >> t) {
while (t--) {
solve();
}
}
return 0;
}

浙公网安备 33010602011771号