「CodeNote」 CF1165D(约数)

Posted by Dawn-K's Blog on November 10, 2019

CF1165D

题意

多组输入t

对于每个输入,给你一个n,给你一个长度为n的序列a.问是否存在一个数,他的所有约数(除了1和它本身),都在这个序列中.

如果有,输出满足条件的最小的数,如果没有,则输出-1

$1<=n<=300$

$2<=a_i<=1e6$

思路

思路很简单,对a数组排序,则约数x如果存在就是a[0]*a[n-1]

那么问题就变成了如何判断x的约数都在集合中.

最开始想的比较朴素,直接就暴力($O(\sqrt{x})$)求出x的所有约数,然后排序去重,和a数组比较.

我感觉理论上是可以过的.因为x最大是1e12,设约数总共c个,总复杂度是O(t*(1e6+300*log300+c*logc))考虑到c不会很大,所以复杂度应该是没有问题的.但是确实是t了

那就换个思路:验证数组a是不是x的所有约数

首先先验证大小上对不对:欧拉筛+唯一分解定理,利用公式求出x的约数的个数,然后减2,判断是否等于n,如果不相等则输出-1

如果相等,则将a数组加入set集合,然后x扫描a数组,判断 if (x % d[i] != 0 || !s.count(x / d[i])) 这里第一次写错了.不仅需要判断d[i]是否是x的约数,还要判断x/d[i]是否也在集合中.

综上所述,此题解决.

AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <bits/stdc++.h>
using namespace std;
#define maxn 3000
#define maxm 100000 + 10
#define ll long long
#define endl '\n'
#define pii pair<int, int>
#define fi first
#define se second
#define pb push_back
ll d[maxn];
set<ll> s;
const int N = 1000000 + 10;
bool prime[N];  // prime[i]表示i是不是质数
int p[N];
ll tot;
void init() {  // 线性筛,每个数只会被筛掉一次
    tot = 0ll;
    for (int i = 2; i < N; i++)
        prime[i] = true;  //初始化为质数
    for (int i = 2; i < N; i++) {
        if (prime[i])
            p[tot++] = i;  //把质数存起来
        for (int j = 0; j < tot && i * p[j] < N; j++) {
            prime[i * p[j]] = false;
            if (i % p[j] == 0)
                break;  //保证每个合数被它最小的质因数筛去
        }
    }
}
vector<pair<ll, ll>> v;
ll CntPrime(ll n) {
    int ans = 1;
    for (int i = 0; i < tot && p[i] * 1ll * p[i] <= n; ++i) {
        if (n % p[i] == 0) {
            int cnt = 0;
            while (n % p[i] == 0) {
                n /= p[i];
                ++cnt;
            }
            ans *= (1 + cnt);
        }
    }
    if (n > 1) {
        ans *= 2;
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(0);
    init();
    int T;
    cin >> T;
    while (T--) {
        s.clear();
        int n;
        cin >> n;
        for (int i = 0; i < n; ++i) {
            cin >> d[i];
            s.insert(d[i]);
        }
        sort(d, d + n);
        ll x = d[0] * d[n - 1];
        bool flag = 0;
        ll ans = CntPrime(x) - 2;
        if (ans == n) {
            for (int i = 0; i < n; ++i) {
                if (x % d[i] != 0 || !s.count(x / d[i])) {
                    flag = 1;
                    break;
                }
            }
            if (flag) {
                cout << -1 << endl;
            } else {
                cout << x << endl;
            }
        } else {
            cout << -1 << endl;
        }
    }
    return 0;
}