传送门
由于要求所有的
d
d
d的答案,我们考虑容斥。
用
f
(
d
)
f(d)
f(d)表示
g
c
d
=
d
gcd=d
gcd=d时的答案。用
F
(
d
)
F(d)
F(d)表示
d
∣
g
c
d
d|gcd
d∣gcd的答案之和。那么我们有:
F
(
n
)
=
∑
n
∣
d
f
(
d
)
⇔
f
(
n
)
=
∑
n
∣
d
μ
(
d
n
)
F
(
d
)
F(n)=\sum_{n|d}f(d) \Leftrightarrow f(n)=\sum_{n|d} \mu(\frac{d}{n}) F(d)
F(n)=n∣d∑f(d)⇔f(n)=n∣d∑μ(nd)F(d)
上式为莫比乌斯反演的一种形式。
那么现在考虑求
F
(
d
)
。
F(d)。
F(d)。令
c
n
t
d
cnt_d
cntd表示
a
a
a数组中有多少个
a
i
a_i
ai为
d
d
d的倍数。
现在每个数都必须是
d
d
d的倍数。也就是说对于那些与
a
a
a不同的
b
b
b,有
m
d
\frac{m}{d}
dm种选择。
现在我们要求有
k
k
k个不相同,也就是说有
N
−
k
N-k
N−k个是相同的。
那么这
N
−
k
N-k
N−k个相同的一定从
c
n
t
d
cnt_d
cntd中选(
d
d
d的倍数)。选不够贡献就是
0
0
0。
相同的选完之后,选不相同的。那么有
c
n
t
d
−
(
N
−
k
)
cnt_d-(N-k)
cntd−(N−k)个只能选
(
m
d
−
1
)
(\frac{m}{d}-1)
(dm−1)个。因为不能和
a
a
a相同。剩下的就可以随便选了。于是我们得到
F
F
F的表达式:
F
(
d
)
=
(
c
n
t
d
N
−
k
)
∗
(
m
d
−
1
)
c
n
t
d
−
(
N
−
k
)
∗
(
m
d
)
N
−
c
n
t
d
F(d)=\tbinom{cnt_d}{N-k}*(\frac{m}{d}-1)^{cnt_d-(N-k)}*(\frac{m}{d})^{N-cnt_d}
F(d)=(N−kcntd)∗(dm−1)cntd−(N−k)∗(dm)N−cntd
那么我们可以先
O
(
m
l
o
g
(
m
)
)
O(mlog(m))
O(mlog(m))处理出
c
n
t
cnt
cnt数组,然后在
O
(
l
o
g
)
O(log)
O(log)的时间内求出
F
F
F(快速幂)。
然后对于每个
f
(
i
)
f(i)
f(i),枚举
i
i
i的倍数。于是
m
1
+
m
2
+
m
3
+
.
.
.
\frac{m}{1}+\frac{m}{2}+\frac{m}{3}+...
1m+2m+3m+...,约为
O
(
m
l
o
g
(
m
)
)
O(mlog(m))
O(mlog(m))。
写代码的时候又犯了一个sb错误。
+
+
v
i
s
[
x
]
++vis[x]
++vis[x]写成了
v
i
s
[
x
]
=
1
vis[x]=1
vis[x]=1,无语。
看来还是变量名字取得不好啊,以后要取恰当一点。。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7,maxn=3e5+10;
int fac[maxn],ifac[maxn];
int n,m,k,cnt[maxn],vis[maxn],x,mx;
int P[maxn],mu[maxn],mark[maxn],tot=0;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return (ll)x*y%mod;}
inline int quickpow(int a,int b,int ret=1){for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
inline int C(int n,int m){
if(m>n) return 0;
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
inline int F(int d){
if(n-k>cnt[d]) return 0;
return mul(C(cnt[d],n-k),mul(quickpow((m/d)-1,cnt[d]-n+k),quickpow(m/d,n-cnt[d])));
}
inline void linear_sieves(int N=maxn){
mark[0]=mark[1]=mu[1]=1;
for(int i=2;i<N;++i){
if(!mark[i]) P[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&i*P[j]<N;++j){
mark[i*P[j]]=1;
if(i%P[j]) mu[i*P[j]]=-mu[i];
else break;
}
}fac[0]=fac[1]=1;
for(int i=2;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=quickpow(fac[N-1],mod-2);
for(int i=N-2;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
}
inline int read(){
int x=0;char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x;
}
int main(){
linear_sieves(),n=read(),m=read(),k=read();
for(int i=1;i<=n;++i) ++vis[x=read()],mx=max(mx,x);
for(int i=1;i<=mx;++i)
for(int j=i;j<=mx;j+=i)
cnt[i]+=vis[j];
for(int i=1;i<=m;++i){
int ans=0;
for(int j=i,t=1;j<=m;j+=i,++t){
if(mu[t]==0) continue;
if(mu[t]==1) ans=add(ans,F(j));
if(mu[t]==-1)ans=dec(ans,F(j));
}printf("%d ",ans);
}
}