CodeForces - 1043F Make It One

題面

題意

給出一串數,求在其中至少選擇幾個數才能使它們的gcd爲1.
數字個數和值域均小於等於300000

做法

首先因爲每個數都小於等於300000,而2357111317>3000002*3*5*7*11*13*17>300000,所以答案至多爲7.
因此我們可以考慮暴力枚舉答案,在判斷此時的答案是否可行時,可以記f[i][j]f[i][j]表示選擇jj個數,使其gcd爲ii的方案數,這個可以用莫比烏斯反演+組合數來求。

代碼

#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");
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章