1. 程式人生 > >BZOJ 4305 數列的GCD 數論

BZOJ 4305 數列的GCD 數論

題目大意:給定n,m和一個長度為n的數列ai..n,其中滿足1aim,對於d=1..m求數列b1..n的個數,滿足:
1.1bim
2.gcd(b1,b2,...,bn)=d
3.ni=1[aibi]=k

k個位置不同就是有nk個位置相同,設s=nk
對於一個d,設a陣列中有cnt個數是d的倍數,那麼答案就是
ansd=Cscnt(md1)cntsmdncntmdi=2ansdi
cnt和後面那個求和式子都能在均攤O(logm)的時間內求出
時間複雜度O(mlogm)

#include <cstdio>
#include <cstring>
#include <iostream> #include <algorithm> #define M 300300 #define MOD 1000000007 using namespace std; int n,m,k; int cnt[M],ans[M]; long long fac[M],inv[M]; long long Quick_Power(long long x,int y) { long long re=1; while(y) { if(y&1) (re*=x)%=MOD; (x*=x)%=MOD; y>>=1
; } return re; } void Pretreatment() { int i; for(fac[0]=1,i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD; for(inv[1]=1,i=2;i<=n;i++) inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD; for(inv[0]=1,i=1;i<=n;i++) (inv[i]*=inv[i-1])%=MOD; } long long C(int n,int m) { return
fac[n] * inv[m] % MOD * inv[n-m] % MOD; } int main() { int i,j,x; cin>>n>>m>>k;k=n-k; Pretreatment(); for(i=1;i<=n;i++) { scanf("%d",&x); ++cnt[x]; } for(i=1;i<=m;i++) { int _cnt=0; for(j=i;j<=m;j+=i) _cnt+=cnt[j]; if(_cnt<k) { ans[i]=0; continue; } ans[i]=C(_cnt,k) * Quick_Power(m/i-1,_cnt-k) % MOD * Quick_Power(m/i,n-_cnt) % MOD; } for(i=m;i;i--) for(j=i+i;j<=m;j+=i) (ans[i]+=MOD-ans[j])%=MOD; for(i=1;i<=m;i++) printf("%d%c",ans[i],i==m?'\n':' '); return 0; }