1. 程式人生 > >bzoj4305 數列的GCD

bzoj4305 數列的GCD

問題 amp 數據 clas 數列 pre csdn -m bzoj

Description

給出一個長度為N的數列{a[n]},1<=a[i]<=M(1<=i<=N)。 現在問題是,對於1到M的每個整數d,有多少個不同的數列b[1], b[2], ..., b[N],滿足: (1)1<=b[i]<=M(1<=i<=N); (2)gcd(b[1], b[2], ..., b[N])=d; (3)恰好有K個位置i使得a[i]<>b[i](1<=i<=N) 註:gcd(x1,x2,...,xn)為x1, x2, ..., xn的最大公約數。 輸出答案對1,000,000,007取模的值。

Input

第一行包含3個整數,N,M,K。 第二行包含N個整數:a[1], a[2], ..., a[N]。

Output

輸出M個整數到一行,第i個整數為當d=i時滿足條件的不同數列{b[n]}的數目mod 1,000,000,007的值。

Sample Input

3 3 3
3 3 3

Sample Output

7 1 0

Hint

當d=1,{b[n]}可以為:(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2), (2, 1, 1), (2, 1, 2), (2, 2, 1)。 當d=2,{b[n]}可以為:(2, 2, 2)。 當d=3,因為{b[n]}必須要有k個數與{a[n]}不同,所以{b[n]}不能為(3, 3, 3),滿足條件的一個都沒有。 對於100%的數據,1<=N,M<=300000, 1<=K<=N, 1<=a[i]<=M。
組合數學 詳見題解:CSDN-> /geotcbrl/article/details/49622731 分為2類: 原數的約數不含 i :必須修改成 i 的倍數(共 m/i 個)。 原數的約數已經含 i :一部分不修改,一部分強制修改(共 m/i-1個) 最後把gcd是 i 的倍數的情況篩掉即可。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=1000000007
; int n,m,k,t[300003]; ll fac[300003],inv[300003],f[300003]; inline ll Pow(ll x,int y){ ll res=1; for(;y;y>>=1){ if(y&1) res=res*x%mod; x=x*x%mod; }return res; } inline ll C(int N,int M) {return fac[N]*inv[M]%mod*inv[N-M]%mod;} int main(){ scanf("%d%d%d",&n,&m,&k); int q; fac[0]=inv[0]=1; for(int i=1;i<=n;++i){ scanf("%d",&q),++t[q]; //開個桶存起來 fac[i]=fac[i-1]*i%mod; inv[i]=inv[i-1]*Pow((ll)i,mod-2)%mod; //預處理出階乘以及其逆元 } for(int i=1;i<=m;++i){ int cnt=0; for(int j=i;j<=m;j+=i) cnt+=t[j]; //統計i的倍數的個數 if(cnt<n-k) continue; f[i]=C(cnt,n-k)*Pow((ll)(m/i-1),cnt-n+k)%mod*Pow((ll)(m/i),n-cnt)%mod;
    //f[i]=對i的倍數強制修改的方案*其他非i倍數的修改方案數 }
for(int i=m;i;--i) //逆序篩去gcd為i的倍數的情況 for(int j=i*2;j<=m;j+=i) f[i]=(f[i]-f[j]+mod)%mod; for(int i=1;i<=m;++i) printf("%lld ",f[i]); return 0; }

bzoj4305 數列的GCD