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;
}