problem
给出一个长度为 n n n 的数列 { a n } \{a_n\} {an}, 1 ≤ a i ≤ m ( 1 ≤ i ≤ n ) 1\le a_i\le m(1\le i\le n) 1≤ai≤m(1≤i≤n)。
现在问题是,对于 1 1 1 到 m m m 的每个整数 d d d,有多少个不同的数列 b 1 , b 2 , . . . , b n b_1, b_2, ..., b_n b1,b2,...,bn,满足:
- 1 ≤ b i ≤ m ( 1 ≤ i ≤ n ) 1\le b_i\le m(1\le i\le n) 1≤bi≤m(1≤i≤n);
- gcd ( b 1 , b 2 , . . . , b n ) = d \gcd(b_1, b_2, ..., b_n)=d gcd(b1,b2,...,bn)=d;
- 恰好有 k k k 个位置 i i i 使得 a i ̸ = b i ( 1 ≤ i ≤ n ) a_i\not= b_i(1\le i\le n) ai̸=bi(1≤i≤n)。
注: gcd ( x 1 , x 2 , . . . , x n ) \gcd(x_1,x_2,...,x_n) gcd(x1,x2,...,xn) 为 x 1 , x 2 , . . . , x n x_1, x_2, ..., x_n x1,x2,...,xn 的最大公约数。
输出答案对 1 0 9 + 7 10^9+7 109+7 取模的值。
数据范围: 1 ≤ n , m ≤ 3 × 1 0 5 1\le n,m\le3\times10^5 1≤n,m≤3×105, 1 ≤ k ≤ n 1\le k\le n 1≤k≤n, 1 ≤ a i ≤ m 1\le a_i\le m 1≤ai≤m。
solution
设 f ( d ) f(d) f(d) 表示 gcd ( b 1 , . . . , b n ) = d \gcd(b_1,...,b_n)=d gcd(b1,...,bn)=d 的答案, F ( d ) = ∑ d ∣ D f ( D ) F(d)=\sum_{d|D}f(D) F(d)=∑d∣Df(D)。
那么我们可以先计算出 F ( d ) F(d) F(d),然后用莫比乌斯反演得到 f ( d ) f(d) f(d)。
我们用 c n t d cnt_d cntd 表示在序列 { a n } \{a_n\} {an} 中,是 d d d 倍数的数的个数。先把 F ( d ) F(d) F(d) 的表达式放上来:
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)=\binom{cnt_d}{n-k}(\lfloor\frac m d\rfloor-1)^{cnt_d-(n-k)}(\lfloor\frac m d\rfloor)^{n-cnt_d} F(d)=(n−kcntd)(⌊dm⌋−1)cntd−(n−k)(⌊dm⌋)n−cntd
接下来就是对这个式子的理解。
首先,由于序列 { b n } \{b_n\} {bn} 的 gcd = d \gcd=d gcd=d,所以每个数都必须是 d d d 的倍数。即如果不加任何限制,每个位置的选法有 ⌊ m d ⌋ \lfloor \frac m d\rfloor ⌊dm⌋ 种。
我们要求要有恰好 k k k 个位置使 a i ≠ b i a_i\ne b_i ai̸=bi,就要选恰好 ( n − k ) (n-k) (n−k) 个位置使 a i = b i a_i=b_i ai=bi。由于只有 c n t d cnt_d cntd 个位置上可能有 a i = b i a_i=b_i ai=bi,所以我们可以从 c n t d cnt_d cntd 中选中 n − k n-k n−k 个,钦定这些位置相等,那就是 ( c n t d n − k ) \binom{cnt_d}{n-k} (n−kcntd)。
剩下的 c n t d − ( n − k ) cnt_d-(n-k) cntd−(n−k) 个位置上,不能有位置相等,所以只有 ⌊ m d ⌋ − 1 \lfloor\frac m d\rfloor-1 ⌊dm⌋−1 种选法,就是 ( ⌊ m d ⌋ − 1 ) c n t d − ( n − k ) (\lfloor\frac m d\rfloor-1)^{cnt_d-(n-k)} (⌊dm⌋−1)cntd−(n−k)。
最后的 n − c n t d n-cnt_d n−cntd 个位置, a i a_i ai 和 b i b_i bi 已经没有机会相等了,这部分的贡献就是 ( ⌊ m d ⌋ ) n − c n t d (\lfloor\frac m d\rfloor)^{n-cnt_d} (⌊dm⌋)n−cntd。
那么最后反演一下,得到:
f ( x ) = ∑ x ∣ d μ ( d x ) F ( d ) f(x)=\sum_{x|d}\mu(\frac d x)F(d) f(x)=x∣d∑μ(xd)F(d)
然后枚举倍数计算答案即可。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)。
code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 300005
#define P 1000000007
using namespace std;
int n,m,k,Max;
int num[N],cnt[N],fac[N],ifac[N],F[N];
int sum,prime[N],mark[N],mu[N];
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return 1ll*x*y%P;}
int power(int a,int b,int ans=1){
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
void linear_sieves(){
mu[1]=1;
for(int i=2;i<N;++i){
if(!mark[i]) prime[++sum]=i,mu[i]=-1;
for(int j=1;j<=sum&&i*prime[j]<N;++j){
mark[i*prime[j]]=1;
if(i%prime[j]==0) {mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
}
void prework(){
fac[0]=fac[1]=1;
for(int i=2;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=power(fac[N-1],P-2);
for(int i=N-2;~i;--i) ifac[i]=mul(ifac[i+1],i+1);
}
int C(int n,int m){
if(n<m) return 0;
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int calc(int d){
if(n-k>cnt[d]) return 0;
return mul(C(cnt[d],n-k),mul(power(m/d-1,cnt[d]-(n-k)),power(m/d,n-cnt[d])));
}
int main(){
scanf("%d%d%d",&n,&m,&k);
linear_sieves(),prework();
for(int i=1,x;i<=n;++i){
scanf("%d",&x);
num[x]++,Max=max(Max,x);
}
for(int i=1;i<=Max;++i)
for(int j=i;j<=Max;j+=i)
cnt[i]+=num[j];
for(int i=1;i<=Max;++i) F[i]=calc(i);
for(int i=1;i<=m;++i){
int ans=0;
for(int j=1;i*j<=m;++j){
if(!mu[j]) continue;
ans=(mu[j]==1)?add(ans,F[i*j]):dec(ans,F[i*j]);
}
printf("%d ",ans);
}
return 0;
}