S
o
u
c
e
:
Souce:
Souce: Codeforces Round #519 by Botan Investments
P
r
o
b
l
e
m
:
Problem:
Problem:给n个数(n<=3e5),每个数<=3e5,选择最少的数,使得他们的gcd为1。输出这个最小子集的大小。
I
d
e
a
:
Idea:
Idea:可以二分,或者直接枚举,因为2 * 3 * 5 * 7 * 11 * 13 * 17 > 3e5,每次选择会删去一个素数,所以答案不超过7。接着用莫比乌斯反演验证答案是否存在,g(x,len)表示集合大小为len,gcd为x的倍数的方案数,那么验证f(1, len)的方案数不为0即可。
C
o
d
e
:
Code:
Code:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 3e5+10;
const int MOD = 1e9+7;
bool isn[N];
int mu[N], p[N];
LL inv[N], fac[N];
void init() {
inv[1] = 1;
for(int i = 2; i < N; ++i) inv[i] = MOD-(MOD/i*inv[MOD%i]%MOD);
fac[0] = 1, inv[0] = 1;
for(int i = 1; i < N; i++){
fac[i] = fac[i-1]*i%MOD;
inv[i] = inv[i-1]*inv[i]%MOD;
}
int pnt = 0;
isn[1] = 1; mu[1] = 1;
for(int i = 2; i < N; i++) {
if(!isn[i]) { p[pnt++] = i; mu[i] = -1; }
for(int j = 0; j<pnt && i*p[j]<N; j++) {
isn[i*p[j]] = 1;
if(i%p[j] == 0) { mu[i*p[j]] = 0; break; }
mu[i*p[j]] = -mu[i];
}
}
}
inline LL C(int a, int b) { return fac[a]*inv[b]%MOD*inv[a-b]%MOD; }
int cnt[N];
int main() {
init();
int n, g; scanf("%d", &n);
for(int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
if(i == 1) g = x;
else g = __gcd(g, x);
cnt[x]++;
}
if(g != 1) { puts("-1"); exit(0); }
for(int i = 1; i < N; i++)
for(int j = i+i; j < N; j += i)
cnt[i] += cnt[j];
for(int i = 1; i <= min(n, 7); i++) {
LL sum = 0;
for(int j = 1; j < N; j++) if(cnt[j] >= i) {
(sum += mu[j]*C(cnt[j], i)) %= MOD;
}
if(sum) { printf("%d\n", i); break; }
}
return 0;
}