简要题意
给出 \(N\),计算:
\[\prod_{i=1}^N\prod_{j=1}^N\frac{\operatorname{lcm}(i,j)}{\gcd(i,j)}\pmod{104857601} \]\(1 \leq N \leq 10^6\)。时间限制 \(200\operatorname{ms}\),空间限制 \(7.81\operatorname{MB}\)。
思路
又是一道没有看题解做出来的反演题。
消灭莫比乌斯反演暴政!世界属于欧拉反演!
首先给出 \(\operatorname{lcm}\) 的定义:
\[\operatorname{lcm}(i,j)=\dfrac{ij}{\gcd(i,j)} \]这个式子非常好用。
然后就可以愉快地推式子了:
\[\begin{aligned} &\prod_{i=1}^N\prod_{j=1}^N\frac{\operatorname{lcm}(i,j)}{\gcd(i,j)}\\ &=\prod_{i=1}^N\prod_{j=1}^N\frac{ij}{\gcd(i,j)^2}\\ &=\dfrac{\prod_{i=1}^N\prod_{j=1}^N{ij}}{\prod_{i=1}^N\prod_{j=1}^N\gcd(i,j)^2}\\ &=\dfrac{\prod_{i=1}^N\prod_{j=1}^N{ij}}{(\prod_{i=1}^N\prod_{j=1}^N\gcd(i,j))^2} \end{aligned} \]把分子分母拆开计算。先算分子:
\[\begin{aligned} &\prod_{i=1}^N\prod_{j=1}^N{ij}\\ &=\prod_{i=1}^N i^n(n!)\\ &=(n!)^n\prod_{i=1}^N i^n\\ &=(n!)^{2n} \end{aligned} \]再算分母中的底数:
\[\begin{aligned} &\prod_{i=1}^N\prod_{j=1}^N\gcd(i,j)\\ &=\prod_{d=1}^N d^{\sum_{i=1}^N\sum_{j=1}^N [\gcd(i,j)=d]} \end{aligned} \]再看指数:
\[\begin{aligned} &\sum_{i=1}^N\sum_{j=1}^N [\gcd(i,j)=d]\\ &=\sum_{i=1}^N\sum_{j=1}^N [\gcd(\lfloor\frac{i}{d}\rfloor,\lfloor\frac{j}{d}\rfloor)=1]\\ &=\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{N}{d}\rfloor}[\gcd(i,j)=1] \end{aligned} \]然后你可以用莫比乌斯反演:
\[\begin{aligned} &\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{N}{d}\rfloor}[\gcd(i,j)=1]\\ &=\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{N}{k}\rfloor}\sum_{k|i,k|j}\mu(d)\\ &=\sum_{k=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{N}{d}\rfloor}[k|i][k|j]\mu(d)\\ &=\sum_{k=1}^{\lfloor\frac{N}{d}\rfloor}\mu(k)\lfloor\frac{N}{kd}\rfloor^2 \end{aligned} \]但这是何必呢?我们可以使用欧拉函数的性质:
\[\begin{aligned} &\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{N}{d}\rfloor}[\gcd(i,j)=1]\\ &=2(\sum_{i=1}^{\lfloor\frac{N}{d}\rfloor}\varphi(i))-1 \end{aligned} \]然后发现指数有一点点大,我们可以使用欧拉定理 \(\gcd(a,M)=1,a^b\equiv a^{b\bmod \varphi(M)}\pmod{M}\) 进行缩小。
时间复杂度 \(O(n\log n)\) 空间复杂度 \(O(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int MOD = 104857601;
inline int M(const long long x,const int mod=MOD){return (x%mod+mod)%mod;}
inline int fact(int x){
long long ret=1;
for(int i=1;i<=x;i++) ret=M(ret*i);
return ret;
}
const int N = 1000005;
int n;
int phi[N];
int pri[N],tot;
void sieve(){
phi[1]=1;
for(int i=2;i<=n;i++){
if(!phi[i]){
pri[++tot]=i;phi[i]=i-1;
}
for(int j=1;j<=tot&&(i*pri[j]<=n);j++){
if(!(i%pri[j])){
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
for(int i=2;i<=n;i++) phi[i]=M(phi[i]+phi[i-1],MOD-1);
}
long long fastpow(long long a,int b,const int mod){
if(b==0) return 1;
if(b==1) return M(a,mod);
long long ret=fastpow(a,b>>1,mod);
ret=M(ret*ret,mod);
if(b&1) ret=M(ret*a);
return ret;
}
signed main(){
cin>>n;
sieve();
long long a=1;
for(int d=1;d<=n;d++) a=M(a*fastpow(d,phi[(n/d)]*2-1,MOD));
cout<<(M(fastpow(fact(n),n<<1,MOD)*fastpow(M(a*a),MOD-2,MOD)));
return 0;
}
标签:lfloor,Product,prod,frac,gcd,sum,rfloor,P5221
From: https://www.cnblogs.com/zheyuanxie/p/p5221.html