bzoj 4305 数列的gcd 【容斥+莫比乌斯反演】

传送门(dark)


SOL

这个说的比较详细了,不再赘述。

在这里插入图片描述

CODE

#include<bits/stdc++.h>
#define pf printf
#define sf scanf
#define cs const
#define ll long long
#define db double
#define in red()
#define gc getchar()
using namespace std;
inline int red(){
    int num=0,f=1;char c=gc ;
    for(;!isdigit(c);c=gc)if(c=='-')f=-1;
    for(;isdigit(c);c=gc)num=num*10+(c^48);
    return num*f;
}
cs int N=3e5+10,mod=1e9+7;

#define ri register int
inline int add(cs int &a,cs int &b){return a+b>mod? a-mod+b:a+b;}
inline int dec(cs int &a,cs int &b){return a-b<0?a+mod-b:a-b;}
inline int mul(cs int &a,cs int &b){return 1ll*a*b%mod;}
inline int ksm(int a,int b){int ans=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ans=mul(ans,a);return ans;}
int mu[N],F[N],f[N],p[N],top,fac[N],ifac[N];
bool vis[N];
inline void init(int lim){
	mu[1]=1;
	for(ri i=2;i<=lim;++i){
		if(!vis[i])p[++top]=i,mu[i]=-1;
		for(ri j=1;j<=top&&1ll*p[j]*i<=lim;++j){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                break;
            }
            mu[i*p[j]]=mu[i]*mu[p[j]];
        }
	}
    fac[0]=1;ifac[0]=1;
    for(ri i=1;i<=lim;++i)fac[i]=mul(fac[i-1],i),ifac[i]=mul(ifac[i-1],ksm(i,mod-2));
}
inline int C(cs int &a,cs int &b){
	if(a==0)return 1;
    return mul(fac[a],mul(ifac[b],ifac[a-b]));
}
int cnt,n,m,K,num[N];
signed main (){

    n=in,m=in,K=in;
    for(ri i=1;i<=n;++i){
    	int k=in;++num[k];    	
	}
    init(max(n,m));
    for(ri d=m;d>=1;--d){
    //	cout<<"begin\n";
     //   cout<<d<<'\n';
        cnt=num[d];
        for(ri i=d*2,k=2;i<=m;i+=d,++k){
            cnt+=num[i];
          //  cout<<cnt<<'\n';
            if(mu[k]>0)f[d]=add(f[d],F[i]);
            else if(mu[k]<0)f[d]=dec(f[d],F[i]);
        }
        if(cnt<n-K)continue;
        F[d]=1ll*ksm(m/d,n-cnt)*C(cnt,n-K)%mod*ksm(m/d-1,cnt+K-n)%mod;
       	f[d]=add(f[d],F[d]);
      //  cout<<"end\n";
    }
    for(ri i=1;i<=m;++i)pf("%d ",f[i]);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值