[CF1043]F. Make It One——容斥原理

题目大意:

给定一个集合,要求你从中选出一些数使得他们的gcd为1,并且使选出的数最少。

思路:

假设最后的答案为x,那么不难发现,这x个数中任意选出x-1个数他们都有公共的因子,并且这些因子互不相同,于是可以得出答案最大为7。
考虑从小到大枚举答案,计算出每种因子d有多少数包含d这个因子,记为(cnt_d)
(f_{i,j})为i个数gcd为j的方案数,从大到小枚举j,不难得到(f_{i,j}={cnt_{j}choose i}-sum_{j|k,k ot=j}f_{i,k})
最后判断一下(f_{i,1})是否有解即可。
时间复杂度(ans imes O(nln n))

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<endl
typedef long long ll;

using namespace std;

void File(){
	freopen("Conscience.in","r",stdin);
	freopen("Conscience.out","w",stdout);
}

template<typename T>void read(T &_){
	T __=0,mul=1; char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-')mul=-1;
		ch=getchar();
	}
	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
	_=__*mul;
}

const int maxn=3e5+10;
const ll mod=1e9+7;
int n,a[maxn],cnt[maxn],bin[maxn];
ll f[maxn],fac[maxn],ifac[maxn];

ll qpow(ll x,ll y){
	ll ret=1; x%=mod;
	while(y){
		if(y&1)ret=ret*x%mod;
		x=x*x%mod;
		y>>=1;
	}
	return ret;
}

void math_init(){
	fac[0]=1;
	REP(i,1,maxn-10)fac[i]=fac[i-1]*i%mod;
	ifac[maxn-10]=qpow(fac[maxn-10],mod-2);
	DREP(i,maxn-11,0)ifac[i]=ifac[i+1]*(i+1)%mod;
}

ll C(ll x,ll y){if(x<y)return 0;return fac[x]*ifac[y]%mod*ifac[x-y]%mod;}

int main(){
	File();
	math_init();
	read(n);
	REP(i,1,n)read(a[i]),++bin[a[i]];
	REP(i,1,maxn-10)for(int j=i;j<=maxn-10;j+=i)cnt[i]+=bin[j];
	REP(i,1,7){
		memset(f,0,sizeof(f));
		DREP(j,maxn-10,1){
			f[j]=C(cnt[j],i);
			for(int k=2*j;k<=maxn-10;k+=j)
				f[j]=(f[j]-f[k])%mod;
			//debug(j); cout<<f[j]<<endl;
		}
		if(f[1])return printf("%d
",i),0;
	}
	puts("-1");
	return 0;
}

原文地址:https://www.cnblogs.com/ylsoi/p/9904101.html