题意简述
给定 n n n和 n n n个数,问:最少选出多少个数能使得它们的 g c d gcd gcd是 1 1 1?
数据
输入
第一行是一个
n
(
n
<
=
3
e
5
)
n(n<=3e5)
n(n<=3e5)。
接下来一行是
n
n
n个数(每个数
<
=
3
e
5
<=3e5
<=3e5)。
输出
最少选出多少个数使得 g c d gcd gcd是 1 1 1。如果选不出来输出 − 1 -1 −1。
样例
输入
3
10 6 15
输出
3
输入
3
2 4 6
输出
-1
输入
7
30 60 21 42 70 15 30
输出
3
思路
我们会发现,前
7
7
7个质数相乘,即
2
∗
3
∗
5
∗
7
∗
11
∗
13
∗
17
=
510510
2*3*5*7*11*13*17=510510
2∗3∗5∗7∗11∗13∗17=510510,超过了
3
e
5
3e5
3e5。所以,如果有答案,肯定在
7
7
7个以内。因为最多的情况,也就是
7
7
7个的情况,是
{
510510
/
2
,
510510
/
3
,
510510
/
5
,
510510
/
7
,
510510
/
11
,
510510
/
13
,
510510
/
17
}
\{510510/2,510510/3,510510/5,510510/7,510510/11,510510/13,510510/17\}
{510510/2,510510/3,510510/5,510510/7,510510/11,510510/13,510510/17}。珂以证明,这
7
7
7个数都
<
=
3
e
5
<=3e5
<=3e5,且
g
c
d
gcd
gcd为
1
1
1。找一下规律,就能明白为什么不能有
8
8
8个了。
那么我们就有了一个暴力的思路:枚举 k k k从 1 1 1到 7 7 7,判断 k k k是否珂行。
那么,如何判断 k k k是否珂行呢?
我们设 f ( g ) f(g) f(g)表示选择 k k k个数使得 g c d = g gcd=g gcd=g有多少种选法。那么,如果能求正确,只要判断 f ( 1 ) f(1) f(1)是否不为 0 0 0,就珂以判断 k k k是否珂行了。珂是怎么求 f ( g ) f(g) f(g)呢?
设 n n n个数中最大的是 m m m, c n t [ i ] cnt[i] cnt[i]表示 n n n个数中有多少 = i =i =i, m u l [ i ] mul[i] mul[i]表示 n n n个数中有多少是 i i i的倍数。如果此时我们要求 n n n个数中选择 k k k个使得 g c d gcd gcd是 g g g的倍数,那非常简单,只要用组合数求 C m u l [ g ] k C_{mul[g]}^{k} Cmul[g]k即珂。然后求出这个之后,减去 g c d gcd gcd是 g g g的两倍以上的,得到的就是 g c d gcd gcd精确为 g g g的情况数,也就是我们要求的 f ( g ) f(g) f(g)。
也就是说, f ( g ) = C m u l [ g ] k − f ( 2 g ) − f ( 3 g ) . . . − f ( 很 多 g ) f(g)=C_{mul[g]}^{k}-f(2g)-f(3g)...-f(很多g) f(g)=Cmul[g]k−f(2g)−f(3g)...−f(很多g),直到减到 很 多 ∗ g > = m 很多*g>=m 很多∗g>=m。我们会发现这个 f f f是和比它大的状态有关的,也就是说,我们在求 f ( g ) f(g) f(g)的时候, f ( 2 g , 3 g . . . ) f(2g,3g...) f(2g,3g...)都要求出来。如何解决这个问题呢?只要逆序枚举 g g g就好了。
还有一个大问题:
怎么求组合数?
恭喜你进入正片。上面都是一些很水的东西。这是这题思维的精华所在,当然也是一个奇怪的技巧。只要鱼锤阶乘,取一下膜,然后打个逆元即珂。取膜。。。就对 1000000007 1000000007 1000000007取膜即珂。
那么,会不会出现这个问题:原本有答案的,由于同余之类的问题,就变成了 0 0 0,导致我们忽略了一个答案?
我告诉你:不会。原因:理论是会的,但是概率很小,足够过这个题了。
代码:
#include<bits/stdc++.h>
using namespace std;
namespace Flandle_Scarlet
{
#define N 300100
#define int long long
#define mod 1000000007
int n,m,a[N];
int cnt[N];//cnt[i]:how many a=i
int mul[N];//mul[i]:how many a is multiple of i
void Input()
{
m=-1;
scanf("%I64d",&n);
for(int i=1;i<=n;++i)
{
scanf("%I64d",&a[i]);
m=max(m,a[i]);
++cnt[a[i]];
}
}
int fact[N];//factor
int ifact[N];//inversion of factor
int qpow(int a,int b,int m)
{
int r=1;
while(b)
{
if (b&1) r=r*a%m;
a=a*a%m,b>>=1;
}
return r;
}
int C(int n,int m)//combination
{
if (n<m) return 0;
int ans=fact[n]*ifact[m]%mod*ifact[n-m]%mod;
//fact[n]/(fact[m]*fact[n-m])
return ans%mod;
}
int f[N],g[N];
//f[i]:choose k,common divisor is i
//g[i]:choose k,Gcd is i
void Soviet()
{
for(int i=1;i<=m;++i)
{
mul[i]=0;
for(int j=i;j<=m;j+=i)
{
mul[i]+=cnt[j];
}
}
fact[0]=1;
for(int i=1;i<=n;++i) fact[i]=fact[i-1]*i%mod;
ifact[n]=qpow(fact[n],mod-2,mod);
for(int i=n-1;i>=0;--i)
{
ifact[i]=(ifact[i+1]*(i+1))%mod;
}//取膜大法
for(int k=1;k<=7;++k)//暴力枚举答案
{
for(int i=m;i>=1;--i)
{
f[i]=C(mul[i],k);
for(int j=(i<<1);j<=m;j+=i)
{
f[i]=(f[i]-f[j]+mod)%mod;//减去倍数
}
}
if (f[1])
{
printf("%I64d\n",k);
return;
}
}
puts("-1");return;
}
void IsMyWife()
{
if (0)
{
freopen("","r",stdin);
freopen("","w",stdout);
}
Input();
Soviet();
}
#undef N //300100
#undef mod //100000007
#undef int //long long
};
int main()
{
Flandle_Scarlet::IsMyWife();
return 0;
}
本文介绍了Codeforces 1043F问题的解决方案,主要涉及如何计算最少选择多少个数使得它们的最大公约数为1。通过分析最大质因数不超过3e5的限制,提出了从1到7枚举子集大小的暴力求解策略。关键在于利用组合数和模逆元计算满足gcd条件的子集数量,通过容斥原理来排除gcd大于1的情况。文章给出了思路及可能遇到的取模误差问题,并提供了部分代码片段。
533

被折叠的 条评论
为什么被折叠?



