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;
}

posted @ 2021-10-06 14:33  Paranoid5  阅读(29)  评论(0编辑  收藏  举报