P6298 齿轮
P6298 齿轮
用dp[i]表示k个数,gcd为i的方案数。
考虑容斥得
\(dp[i] = sum-f[2i]-f[3i]-...-f[ki]\)
sum表示,gcd为i的倍数的的方案数。
枚举的时候,只枚举倍数,所以是\(\frac{m}{1}+\frac{m}{2}+...+\frac{m}{m}\)
调和级数求和\(logm\),加上预处理阶乘逆元,所以时间复杂度为\(n+mlogm\)。
#include <iostream>
#include <queue>
#include <cstring>
#include <map>
#include <stack>
#define ll long long
const ll N = (1<<20)+50,M = 150;
const ll inf = 0x3f3f3f3f;
const ll mod = 1e9+7;
using namespace std;
ll f[N],inv[N],vis[N],sum[N],dp[N];
ll f_pow(ll a,ll b){
ll res = 1;
while(b){
if(b&1)res = res*a%mod;
b>>=1;
a = a*a%mod;
}
return res%mod;
}
void init(){
f[0] = 1;
for(ll i = 1;i < N;i++)f[i] = f[i-1]*i%mod;
inv[N-1] = f_pow(f[N-1],mod-2);
for(ll 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;
}
ll n,m,k;
int main() {
init();
cin>>n>>m>>k;
for(ll i = 1,x;i <= n;i++){
cin>>x;
vis[x]++;
}
for(ll i = m;i;i--){
ll cnt = 0;
for(ll j = i;j <= m;j+=i){
cnt += vis[j];
dp[i] = (dp[i]-dp[j]+mod)%mod;
}
dp[i] = (dp[i]+C(cnt,k)+mod)%mod;
}
for(ll i = 1;i <= m;i++) cout<<dp[i]<<' ';
return 0;
}