题意
给出长度为 n n n的正整数序列,要求找出一个最小的子集,使得子集中的数的gcd等于1。没有的话输出-1,否则输出子集大小。序列中的数 0 ≤ a i ≤ 300000 0 \leq a_i \leq 300000 0≤ai≤300000。
题解
暴力的做法就是从1开始枚举子集的大小,不同的子集个数 2 n 2^n 2n,肯定要超时。我们可以设 d p [ i ] [ j ] dp[i][j] dp[i][j]表示集合大小为 i i i且集合 g c d gcd gcd等于 j j j的集合个数。当 d p [ i ] [ 1 ] > 0 dp[i][1]>0 dp[i][1]>0时,说明存在集合大小为 i i i的且其 g c d = 1 gcd=1 gcd=1。
这里可以采取容斥来解决, d p [ i ] [ j ] = C ( i , c n t j ) − ∑ k = 0 n d p [ i ] [ k ] , j ∣ k 。 dp[i][j] = C(i,cnt_j)-\sum_{k=0}^{n}dp[i][k], j|k。 dp[i][j]=C(i,cntj)−∑k=0ndp[i][k],j∣k。
c
n
t
j
:
cnt_j:
cntj:序列中能被
j
j
j整除的数的个数。
C
(
i
,
c
n
t
j
)
C(i,cnt_j)
C(i,cntj):在序列中能被
j
j
j整除的数中选
i
i
i个。
为什么这么减呢?因为 C ( i , c n t j ) 选 出 来 的 数 的 集 合 C(i,cnt_j)选出来的数的集合 C(i,cntj)选出来的数的集合可能包括了能被 2 j , 3 j , . . , k j 2j,3j,..,kj 2j,3j,..,kj整除的集合。
这里 i i i的大小最大不超过7,因为要保证所有数互质,因为6个数不互质,7个数一定互质,那么每个数必须包含6个质因子。举个例子来说, 10 ,6 ,15 其质因子组成是 (2,5), (2,3), (3,5),每当gcd两个,都会消去不同质因子,比如 g c d [ ( 2 , 5 ) , ( 2 , 3 ) ] = 2 gcd[(2,5),(2,3)] = 2 gcd[(2,5),(2,3)]=2,所以如果7个数要够消的话,那么一个数要有6个质因子,每和一个数gcd就消去一个。
构造一下7个数的情况。
[
2
∗
3
∗
5
∗
7
∗
11
∗
13
]
,
[
2
∗
5
∗
7
∗
11
∗
13
∗
17
]
,
[
2
∗
3
∗
7
∗
11
∗
13
∗
17
]
,
[
2
∗
3
∗
5
∗
11
∗
13
∗
17
]
,
[
2
∗
3
∗
5
∗
7
∗
13
∗
17
]
,
[
2
∗
3
∗
5
∗
7
∗
13
∗
15
]
,
[
3
∗
5
∗
7
∗
11
∗
13
∗
17
]
[2*3*5*7*11*13],[2*5*7*11*13*17],[2*3*7*11*13*17],[2*3*5*11*13*17],[2*3*5*7*13*17],[2*3*5*7*13*15],[3*5*7*11*13*17]
[2∗3∗5∗7∗11∗13],[2∗5∗7∗11∗13∗17],[2∗3∗7∗11∗13∗17],[2∗3∗5∗11∗13∗17],[2∗3∗5∗7∗13∗17],[2∗3∗5∗7∗13∗15],[3∗5∗7∗11∗13∗17]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5+5;
const int N = 3e5;
const int mod = 1e9+7;
ll dp[maxn];
int fen[maxn], mu[maxn];
ll pow_mod(ll x, ll n) {
ll res = 1;
while(n) {
if(n&1) res = res*x%mod;
x = x*x%mod;
n >>= 1;
}
return res;
}
// 组合数阶乘预处理
void init() {
fen[0] = 1;
for(int i = 1; i <= N; ++i)
fen[i] = 1ll*fen[i-1]*i%mod;
mu[N] = pow_mod(fen[N],mod-2);
// cout << mu[N-1] << endl;
for(int i = N; i >= 1; --i) {
mu[i-1] = 1ll*mu[i]*i%mod;
// cout << mu[i] << endl;
}
}
int C(int a,int b) {
if(b < 0 || a < b) return 0;
return 1ll*fen[a]*mu[b]%mod*mu[a-b]%mod;
}
int cnt[maxn];
int main() {
init();
int n;
// cout << fen[1] <<" " << mu[1] <<" " << mu[0] << endl;
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
int x;
scanf("%d", &x);
cnt[x]++;
}
for(int i = 1; i <= N; ++i)
for(int j = 2*i; j <= N; j += i) {
cnt[i] += cnt[j];
}
// cout << cnt[15] << endl;
for(int i = 1; i <= 10; ++i) {
for(int j = N; j >= 1; --j) {
dp[j] = C(cnt[j], i);
// cout <<i <<" " << j <<" " << dp[j] << endl;
for(int k = j+j; k <= N; k += j)
dp[j] = (dp[j]-dp[k]+mod)%mod;
}
if(dp[1] > 0) {
printf("%d\n", i);
exit(0);
}
}
puts("-1");
return 0;
}