洛谷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]); }