题目链接:F
题意:给一串数字,让你从中找出最少的数字,使得它们的最大公约数为1。
参考链接:https://blog.csdn.net/Link_Ray/article/details/83627570
题解:由2 * 3 * 5 * 7 * 11 * 13 * 17 > 3e5 ,我们可以知道,最多不超过7个,假设有7个数字,要想每个数字都互质,每个数字必须包含6个质因子,因为每两个数GCD,会删掉不同的质因子(例如 10和6 gcd(5*2,2*3)=2(删掉了3,5),假如没得删掉的话,那么就不用7个数字了,因为没有不同的质因子可删了,那么此时就已经满足最大公约数为1。所以如果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]
我们设 dp[i][j] 表示集合大小为i,gcd为j的集合的方案数。当dp[i][1]>0时,说明存在大小为i且gcd为1的集合。
这里采用组合数学来解决,dp[i][j]=C( cnt[j] , i ) - dp[i][k] , j|k。
cnt[j] :序列中能被 j 整除的数的个数。
C(cnt[j],i ): 在序列中能被 j 整除的数中选 i 个。
为什么这么减呢?因为C(cnt[j] , i )选出来的数的集合可能包括了能被2j,3j,..,kj 整除的集合。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const LL mod=1e9+7;
const int maxn=3e5+10;
const int N=3e5;
int jie[maxn],ni[maxn];
LL pow(int x,int y)
{
LL sum=1;
while(y)
{
if(y&1) sum=sum*x%mod;
x=x*x%mod;
y>>=1;
}
return sum;
}
void init()
{
jie[0]=jie[1]=1;
for(int i=2;i<=N;i++)
jie[i]=1LL*jie[i-1]*i%mod; ///前i项的阶乘
ni[N]=pow(jie[N],mod-2); ///逆元
for(int i=N;i>=1;i--) ///线性筛逆元
{
ni[i-1]=1LL*ni[i]*i%mod;
}
}
int C(int a,int b)
{
if(b<0||a<b) return 0;
return 1LL*jie[a]*ni[b]%mod*ni[a-b]%mod;
}
int dp[maxn],cnt[maxn];
int main()
{
init();
int n;
while(~scanf("%d",&n))
{
memset(cnt,0,sizeof(cnt));
int x;
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
cnt[x]++; ///存储值为x的,有多少个?
}
for(int i=1;i<=N;i++) ///求序列中能被i整除的个数
for(int j=2*i;j<=N;j+=i)
cnt[i]+=cnt[j];
memset(dp,0,sizeof(dp));
bool flag=true;
for(int i=1;i<8;i++) ///集合大小为i
{
for(int j=N;j>=1;j--){ ///gcd为j
dp[j]=C(cnt[j],i);
for(int k=2*j;k<=N;k+=j){ ///减掉不符合
dp[j]=(dp[j]-dp[k]+mod)%mod;
}
}
if(dp[1]) { ///说明存在集合大小为i,gcd为1的方案,直接输出
printf("%d\n",i);flag=false;
break;
}
}
if(flag) puts("-1"); ///不存在,输出-1
}
return 0;
}