洛谷P6298 齿轮

https://www.luogu.com.cn/problem/P6298

 

对于每一个t,设答案为f(t)

f(t)=C(能被t整除的数的个数,k)- Σf(i) t能整除i

所以从大到小倒着计算f即可

求能被x整除的数的个数,令x不断翻倍,x,2x,3x……

这样时间复杂度=n/1+n/2+n/3+……n/n=nlog(n)

 

#include<cstdio>

using namespace std;

#define N 1000001

int sum[N],div[N];
int ans[N];
int fac[N],inv[N];

const int mod=1e9+7;

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

int poww(int a,int b)
{
    int s=1;
    for(;b;a=1ll*a*a%mod,b>>=1)
        if(b&1) s=1ll*s*a%mod;
    return s;
}

int main()
{
    int n,m,k,x;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;++i) 
    {
        scanf("%d",&x);
        sum[x]++;
    }
    for(int i=1;i<=m;++i)
        for(int j=i;j<=m;j+=i)
            div[i]+=sum[j];
    fac[0]=1;
    for(int i=1;i<=n;++i) fac[i]=1ll*fac[i-1]*i%mod;
    for(int i=0;i<=n;++i) inv[i]=poww(fac[i],mod-2);
    for(int i=m;i;--i)
    {
        ans[i]=C(div[i],k);
        for(int j=i+i;j<=m;j+=i) ans[i]=(ans[i]-ans[j]+mod)%mod;
    }
    for(int i=1;i<=m;++i) printf("%d ",ans[i]); 
}

 

posted @ 2020-10-05 21:12  TRTTG  阅读(240)  评论(0编辑  收藏  举报