链接
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;
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; }
|