Avatar
“”

一个兴趣使然的追梦人

▼

#题解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. 算法设计

  1. 预处理小范围素数(例如线性筛预处理前 \(10^5\) 以内的素数,实际上预处理前 100 个质数就完全足够)。
  2. 从最小的质数 \(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;
}
posted @ 2026-09-28 15:16  hermanO  阅读(5)  评论(0)    收藏  举报