洛谷——P6298 齿轮

题目描述

Daniel13265 从不知哪里找来了 nn 个齿轮,第 ii 个齿轮的齿数为不超过 mm 的正整数 a_ia
i

。他现在想把其中 kk 个齿轮按照一定的方式拼接在一起。

当齿轮使用一段时间后,就会产生损耗。一个齿轮组的损耗速率是由这个齿轮组的所有齿轮齿数的最大公约数决定的:最大公约数越大,相同的齿之间啮合的频率就会增高,从而损耗的速率就会变快。这个最大公约数又被称为损耗因子。

算出一个齿轮组的损耗因子是很容易的。可是现在 Daniel13265 想要知道,对于可能拼接出的所有齿轮组的损耗因子。

Daniel13265 知道拼接出损耗因子大于 mm 的齿轮组是不可能的,而且由于可能拼出的齿轮组的个数很多,你只需要反过来告诉他对于所有的 t\in[1, m]t∈[1,m],能够拼接出的损耗因子为 tt 的齿轮组的个数对 10^9+710
9
+7 取模后的结果即可。

输入格式

输入共 2 行。
第一行包含三个正整数 n,m,分别表示 Daniel13265 拥有的齿轮个数,齿轮齿数的最大可能值与 Daniel13265 期望的齿轮组的齿轮个数。
第二行共 nn 个用单个空格隔开的正整数,第 i 个数 ai 表示第 i 个齿轮的齿数。

输出格式

输出一行 m 个整数,第 t 个数表示能够拼接出的损耗因子为 t 的齿轮组的个数对 10^9+7 取模后的结果。

输入输出样例

输入 #1
5 6 2
1 2 3 4 6
输出 #1
6 3 1 0 0 0

说明/提示

样例解释

损耗因子为 11 的齿轮组有 (1,2),(1,3),(1,4),(1,6),(2,3),(3,4) 共 6 个;
损耗因子为 22 的齿轮组有 (2,4),(2,6),(4,6) 共 3 个;
损耗因子为 33 的齿轮组有 (3,6) 共 1 个。

容斥

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const ll mod=1e9+7;
const int N=1e6+500;

ll f[N],inv[N],vis[N],ans[N];

ll qpow(ll a,ll b){
	ll ans=1;
	while(b){
		if(b&1)ans=ans*a%mod;
		b>>=1;
		a=a*a%mod;
	}
	return ans;
}

void init(){
	f[0]=1;
	for(int i=1;i<N;++i){
		f[i]=f[i-1]*i%mod;
	}
	inv[N-1]=qpow(f[N-1],mod-2);
	for(int i=N-2;i>=0;--i){
		inv[i]=inv[i+1]*(i+1)%mod;
	}
}

ll C(ll n,ll m){
	if(n<m)return 0;
	return (f[n]*inv[m]%mod)*inv[n-m]%mod;
}

int main(){
	init();
	ll n,m,k;
	cin>>n>>m>>k;
	for(int i=1;i<=n;++i){
		int x;
		scanf("%d",&x);
		vis[x]++;
	}
	for(int i=m;i;--i){
		ll cut=0;
		for(int j=1;j*i<=m;++j){
			cut+=vis[i*j];
			ans[i]=(ans[i]-ans[i*j]+mod)%mod;
		}
		ans[i]=(ans[i]+C(cut,k)+mod)%mod;
	}
	for(int i=1;i<=m;++i){
		printf("%lld ",ans[i]);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值