bzoj4305: 数列的GCD
要求k个与原序列中的数不同,就是要求(n-k)个相同,令K=n-k
然后cnt[i]表示序列a中i的倍数的个数
f[i]表示gcd为i的倍数的方案数
f[i]=C(cnt[i],K)*(m/i-1)^(cnt[i]-K)*(m/i)^(n-cnt[i])
那么ans[i]=f[i]-sigma(ans[j]) (j%i==0)
cnt和组合数都可以在nlogn内预处理
所以复杂度nlogn
详见代码
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #define ll long long #define N 300005 #define P 1000000007 using namespace std; inline int read(){ int ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } int pow2(int x,int y){ int ret=1; while (y){ if (y&1) ret=(ll)ret*x%P; y=y>>1; x=(ll)x*x%P; } return ret; } int n,m,K; int a[N]; int cc[N]; int cnt[N]; void precompute(){ memset(cnt,0,sizeof(cnt)); for (int i=1;i<=n;++i) ++cnt[a[i]]; for (int i=1;i<=m;++i) for (int j=2;i*j<=m;++j) cnt[i]+=cnt[i*j]; cc[K]=1; for (int i=K+1;i<=n;++i) cc[i]=(ll)cc[i-1]*pow2(i-K,P-2)%P*i%P; } int ans[N]; int main(){ n=read();m=read();K=n-read(); for (int i=1;i<=n;++i) a[i]=read(); precompute(); for (int i=m;i;--i)if (cnt[i]>=K){ ans[i]=(ll)cc[cnt[i]]*pow2(m/i-1,cnt[i]-K)%P*pow2(m/i,n-cnt[i])%P; for (int j=2;i*j<=m;++j) (ans[i]-=ans[i*j]-P)%=P; } else ans[i]=0; for (int i=1;i<m;++i) printf("%d ",ans[i]); printf("%d\n",ans[m]); return 0; }