Godzillad

描述:

给定 \(n\) 个数,求其中取 \(k\) 个数,它们的 \(\gcd\)\(t\) ,其中 \(t∈[1,m]\)

思路:

套路:

这里是求多个数的 \(\gcd\)\(t\) ,那么可以设 \(f(i)\) 表示用 \(k\) 个数,组合是 \(i\) 的的方案数。

那么可以用容斥:

\(f(i)=sum-f(2i)-f(3i)-f(4i)\dots f(ki)\)

其中 \(sum\) 为组合是 \(i\)倍数 的方案数, \(ki\) 为不大于 \(n\) 的最大整数。

注意这里要倒序枚举,不然会出错。

预处理阶乘 \(O(n)\) ,求 \(f(i)\)\(m\log m\) ,即 \(\dfrac{m}{1}+\dfrac{m}{2}+\dots \dfrac{m}{m}\)

这里会用到 乘法逆元 预处理组合数。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>

#define LL long long
#define PR pair<int,int>

using namespace std;

const int kN=1e6;
const int kMod=1e9+7;

int n,m,k;
int a[kN+5];
int num[kN+5];
LL fac[kN+5],inv[kN+5];
LL f[kN+5];

int v[kN];

LL Qpow(LL a,LL b){
	LL res=1;
	for(int i=0;(1<<i)<=b;++i){
		if(b&(1<<i)){
			res=(res*a)%kMod;
		}
		a=(a*a)%kMod;
	}
	return res;
}

void Init(){
	fac[0]=1;
	for(int i=1;i<=kN;++i){
		fac[i]=(fac[i-1]*i)%kMod;
	}
	inv[kN]=Qpow(fac[kN],kMod-2);
	for(int i=kN-1;i>=0;--i){
		inv[i]=inv[i+1]*(i+1)%kMod;
	}
}

LL C(LL n,LL m){
	return fac[n]*inv[m]%kMod*inv[n-m]%kMod;
}

int main(){
	Init();
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;++i){
		scanf("%d",&a[i]);
		v[a[i]]++;
	}
	for(int i=1;i<=m;++i){
		for(int j=i;j<=m;j+=i){
			if(!v[j]){continue;}
			num[i]+=v[j];
		}
	}
	for(int i=m;i;--i){
		if(!num[i]||num[i]<k){continue;}
		f[i]=C(num[i],k);
		for(int j=2*i;j<=m;j+=i){
			f[i]-=f[j];
			f[i]=(f[i]+kMod)%kMod;
		}
	}
	for(int i=1;i<=m;++i){
		printf("%lld ",f[i]);
	}
	return 0;
}

分类:

技术点:

相关文章:

  • 2022-12-23
  • 2021-09-17
  • 2021-10-16
  • 2021-12-29
  • 2021-05-27
  • 2021-12-28
  • 2022-01-07
猜你喜欢
  • 2022-01-20
  • 2021-06-05
  • 2022-02-17
  • 2021-08-03
  • 2021-07-18
  • 2021-10-01
  • 2022-12-23
相关资源
相似解决方案