题目大意:给定
n,m
和一个长度为
n
的数列
1. 1≤bi≤m
2. gcd(b1,b2,...,bn)=d
3. ∑ni=1[ai≠bi]=k
有
k
个位置不同就是有
对于一个
d
,设
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;
}