Coprime(埃氏筛)

题意

给定一个长度为\(n\)的整数序列\(A\),第\(i\)个元素为\(A_i\)

  • 若任意两个元素互质,则称该序列为pairwise coprime。
  • 若该序列不是pairwise coprime,且所有元素互质,则称该序列为setwise coprime
    问该序列是pairwise coprime还是setwise coprime,还是都不是

数据范围

\(2 \leq n \leq 10^6\)
\(1 \leq A_i \leq 10^6\)

思路

首先判断setwise coprime,那就是将所有元素求gcd,然后判断是否是\(1\)即可。

重点是判断任意两个元素是否是互质的。我们考虑将所有数分解质因数,如果所有质数都不相同,那么该序列中的元素是两两互质的。

如果直接试除法分解每个元素,时间复杂度太高,要想更快的做法。
我们考虑埃氏筛,在筛的过程中,每个合数都可以被其所有质因子筛一遍,这就相当于对每个数分解质因数了。
具体来说,对于每个质数\(p\),如果它能够筛掉序列中的两个及以上的数,那么该序列就不是pairwise coprime。
判断是否是序列中的数,可以使用map。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>

using namespace std;

const int N = 1000010;

int n;
int a[N];

unordered_map<int, int> mp;

bool st[N];

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    scanf("%d", &n);
    int s;
    for(int i = 1; i <= n; i ++) {
        int x;
        scanf("%d", &x);
        a[i] = x;
        mp[x] ++;
        if(i == 1) s = x;
        else s = gcd(s, x);
    }
    bool f1 = true, f2 = false;
    if(s == 1) f2 = true;
    for(int i = 2; i < N; i ++) {
        if(st[i]) continue;
        if(!f1) break;
        st[i] = true;
        int cnt = 0;
        for(int j = i; j < N; j += i) {
            st[j] = true;
            if(mp[j] >= 1) cnt += mp[j];
            if(cnt >= 2) {
                f1 = false;
                break;
            }
        }
    }
    if(f1) printf("pairwise coprime\n");
    else if(f2) printf("setwise coprime\n");
    else printf("not coprime\n");
    return 0;
}
posted @ 2022-03-29 19:54  pbc的成长之路  阅读(137)  评论(0编辑  收藏  举报