CodeForces - 1043F Make It One

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yzyyylx/article/details/83656701

题面

题意

给出一串数,求在其中至少选择几个数才能使它们的gcd为1.
数字个数和值域均小于等于300000

做法

首先因为每个数都小于等于300000,而 2 3 5 7 11 13 17 > 300000 2*3*5*7*11*13*17>300000 ,所以答案至多为7.
因此我们可以考虑暴力枚举答案,在判断此时的答案是否可行时,可以记 f [ i ] [ j ] f[i][j] 表示选择 j j 个数,使其gcd为 i i 的方案数,这个可以用莫比乌斯反演+组合数来求。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 300100
#define MN 300000
#define M 998244353
using namespace std;

ll n,zs[N],miu[N],cnt[N],qc[N],jc[N],zz,g;
bool P[N];

inline void get()
{
	ll i,j,t;
	miu[1]=jc[0]=jc[1]=1;
	for(i=2;i<=MN;i++)
	{
		jc[i]=jc[i-1]*i%M;
		if(!P[i])
		{
			zs[++zz]=i;
			miu[i]=-1;
		}
		for(j=1;j<=zz;j++)
		{
			t=zs[j]*i;
			if(t>MN) break;
			P[t]=1;
			if(i%zs[j]) miu[t]=-miu[i];
			else
			{
				miu[t]=0;
				break;
			}
		}
	}
	for(i=1;i<=MN;i++) for(j=i;j<=MN;j+=i) qc[i]+=cnt[j];
}

inline ll po(ll u,ll v)
{
	ll res=1;
	for(;v;)
	{
		if(v&1) res=res*u%M;
		u=u*u%M;
		v>>=1;
	}
	return res;
}

inline ll C(ll u,ll v)
{
	if(u<v) return 0;
	return jc[u]*po(jc[v],M-2)%M*po(jc[u-v],M-2)%M;
}

ll calc(ll u)
{
	ll i,res=0;
	for(i=1;i<=MN;i++)
	{
		res+=miu[i]*C(qc[i],u);
		res%=M;
	}
}

int main()
{
	ll i,j,p;
	cin>>n;
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&p);
		cnt[p]++;
	}
	get();
	for(i=1;i<=min(n,7ll);i++)
	{
		if(calc(i))
		{
			cout<<i;
			return 0;
		}
	}
	puts("-1");
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/83656701