CF1043F Make It One

题目

CF1043F Make It One

分析

首先就需要看出一个性质:如果有解,那么答案必然不超过 \(7\)

为什么?

考虑两个数取 \(gcd\) 会造成什么影响:原数至少 \(/2\)!(因为这里我们选的两个数必然不同,否则就不用选)

然后发现这样的话可以选的数并不多,再进一步发现这里其实是 \(7\) ,因为每一次其实是在除以一个质数,且值域只有 \(3e5\)

接下来我们知道其实这样的“给出一个集合”的题目一般来说是不能直接标准的线性dp来做的,而是应该在整体的值域上面多想想,但是我们发现似乎值域也不好想,于是考虑直接从这个性质入手。

考虑枚举答案 \(1,2,3...7\)

然后就是个标准的反演柿子?但是我们这里考虑直接容斥。

\(f_i\) 表示选了 \(k\) 个数,它们的 \(gcd\) 具有因数 \(i\) 的方案数,显然是 \(\dbinom{cnt[i]}{k}\) ,其中 \(cnt[i]\) 表示原集合中是 \(i\) 的倍数的数的个数。

\(g_i\) 表示选了 \(k\) 个数,它们的 \(gcd\) 等于 \(i\) 的方案数。

显然 \(g\) 可以通过容斥得到:\(g[i]=f[i]-\sum\limits_{j=2}^{i\cdot j\le V}g[i\times j]\)

最后判断 \(g[1]\) 是否有值即可。

还有一个注意的地方,因为这里的容斥要算的方案数太大,我们只能直接选取一个模数来求方案数,其实是有可能出错的(就相当于哈希),所以这里也可以高精(但是会超时),也可以双哈希来提高准确率。

代码

#include<bits/stdc++.h>
using namespace std;
//#ifdef ONLINE_JUDGE
//	#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//	char buf[1<<21],*p1=buf,*p2=buf;
//#endif
template<typename T>
inline void read(T &x){
	x=0;bool f=false;char ch=getchar();
	while(!isdigit(ch)){f|=ch=='-';ch=getchar();}
	while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template<typename T>
inline void write(T x){
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
#define ull unsigned long long
#define ld long double
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define pc putchar
#define PII pair<int,int>
#define rep(i,x,y) for(register int i=(x);i<=(y);i++)
#define dep(i,y,x) for(register int i=(y);i>=(x);i--)
const int MOD=1e9+7;
inline int inc(int x,int y){x+=y;return x>=MOD?x-MOD:x;}
inline int dec(int x,int y){x-=y;return x<0?x+MOD:x;}
inline void incc(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
inline void decc(int &x,int y){x-=y;if(x<0) x+=MOD;}
inline void chkmin(int &x,int y){if(y<x) x=y;}
inline void chkmax(int &x,int y){if(y>x) x=y;}
const int N=1e6+5,M=2e5+5,INF=1e9+7,V=3e5;
int n,a[N],t[N],cnt[N],fac[N],ifac[N];
int Cnm(int x,int y){
	if(x<y) return 0;
	return 1ll*fac[x]*ifac[x-y]%MOD*ifac[y]%MOD;
}
int QuickPow(int x,int y=MOD-2){
	int res=1;
	while(y){
		if(y&1) res=1ll*res*x%MOD;
		y>>=1;
		x=1ll*x*x%MOD;
	}
	return res;
}
int f[N],g[N];
void Calc(int k){
	for(int i=1;i<=V;i++) f[i]=g[i]=Cnm(cnt[i],k);
	for(int i=V;i>=1;i--){
		for(int j=i*2;j<=V;j+=i){
			decc(g[i],g[j]);
		}
	}
	return ;
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(false);
//	double ST=clock();
	read(n);
	for(int i=1;i<=n;i++) read(a[i]),t[a[i]]++;
	for(int i=1;i<=V;i++){
		for(int j=i;j<=V;j+=i){
			incc(cnt[i],t[j]);
		}
	}
	fac[0]=1;
	for(int i=1;i<=V;i++) fac[i]=1ll*fac[i-1]*i%MOD;
	ifac[V]=QuickPow(fac[V],MOD-2);
	for(int i=V-1;i>=1;i--) ifac[i]=1ll*ifac[i+1]*(i+1)%MOD;ifac[0]=1;
	for(int i=1;i<=7;i++){
		Calc(i);
		if(g[1]) return write(i),0;
	}
	puts("-1");
//#ifndef ONLINE_JUDGE
//	cerr<<"\nTime:"<<(clock()-ST)/CLOCKS_PER_SEC<<"s\n";
//#endif
	return 0;
}
/*
2
5 
4 1 2 4 5 3 1 2 3 5
3
3 2 1 2 1 3
*/



posted @ 2021-10-26 21:22  __Anchor  阅读(22)  评论(0编辑  收藏  举报