HDU 4675. GCD of Sequence

链接

http://acm.hdu.edu.cn/showproblem.php?pid=4675

题意

求 $1\le b_i \le M$,有 $k$ 个位置 $a_i\neq b_i$ 且 $\gcd(b_1,b_2,\dots,b_n)=d$ $(1\le d \le M)$ 的数组 $b$ 的方案数。

思路

根据莫比乌斯反演公式 $F(n)=\sum_{n\mid d}f(d)\Leftrightarrow f(n)=\sum_{n\mid d}\mu(\frac{d}{n})F(d)$,

记 $f(d)$ 为 $1\le b_i \le M$,有 $k$ 个位置 $a_i\neq b_i$ 且 $\gcd(b_1,b_2,\dots,b_n)=d$ 的数组 $b$ 的方案数,

记 $F(d)$ 为 $1\le b_i \le M$,有 $k$ 个位置 $a_i\neq b_i$ 且 $d\mid \gcd(b_1,b_2,\dots,b_n)$ 的数组 $b$ 的方案数。

记 $cnt_i$ 为 $a$ 中为 $i$ 的倍数的个数,$O(m\log m)$ 预处理。

对于最大公因数 $d$,$a$ 中不是 $d$ 的倍数的个数为 $n-cnt_d$ 个。

  • 当 $n-cnt_d>k$ 时,$F(d)=0$。
  • 当 $n-cnt_d\le k$ 时,这 $n-cnt_d$ 个数都有 $\lfloor\frac{N}{d}\rfloor$ 个选择,共 $\lfloor\frac{N}{d}\rfloor!$ 个情况,剩下 $k-n+cnt_d$ 个数需要改变,共 $\binom{cnt_d}{k-n+cnt_d}(\lfloor\frac{N}{d}\rfloor-1)!$ 个情况,所以 $F(d)=\lfloor\frac{N}{d}\rfloor!\binom{cnt_d}{k-n+cnt_d}(\lfloor\frac{N}{d}\rfloor-1)!$。

暴力枚举 $d$ 计算 $f(d)$,每次询问都是 $O(m\log m)$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
// head
const LL MOD=1e9+7;
const int N=3e5+5;
LL fac[N],invfac[N],F[N],res[N];
int cnt[N],mn[N],mu[N];
VI p;
void get_mu(int n) {
mu[1]=1;
for(int i=2;i<=n;i++) {
if(!mn[i]) mn[i]=i,mu[i]=-1,p.PB(i);
for(auto x:p) {
if(x*i>n) break;
mn[x*i]=x;
if(i%x==0) {mu[x*i]=0;break;}
mu[x*i]=-mu[i];
}
}
}
LL qpow(LL a,LL b) {
LL ret=1;
while(b) {
if(b&1) ret=ret*a%MOD;
a=a*a%MOD;
b>>=1;
}
return ret;
}
void init_invfac(LL n) {
n=min(n,MOD-1);
fac[0]=1;
for(LL i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
invfac[n]=qpow(fac[n],MOD-2);
for(LL i=n-1;~i;i--) invfac[i]=invfac[i+1]*(i+1)%MOD;
}
LL C(int n,int m) {
return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init_invfac(3e5);
get_mu(3e5);
int n,m,k;
while(cin>>n>>m>>k) {
for(int i=1;i<=m;i++) cnt[i]=0;
for(int i=1;i<=n;i++) {
int x;cin>>x;
++cnt[x];
}
for(int i=1;i<=m;i++)
for(int j=i*2;j<=m;j+=i)
cnt[i]+=cnt[j];
for(int i=1;i<=m;i++) {
if(n-cnt[i]<=k) F[i]=qpow(m/i,n-cnt[i])*C(cnt[i],k-n+cnt[i])%MOD*qpow(m/i-1,k-n+cnt[i])%MOD;
else F[i]=0;
}
for(int i=1;i<=m;i++) {
res[i]=0;
for(int j=i;j<=m;j+=i)
res[i]=(res[i]+mu[j/i]*F[j])%MOD;
}
for(int i=1;i<=m;i++) cout<<(res[i]+MOD)%MOD<<" \n"[i==m];
}
return 0;
}