( ext{Solution:})
(Question:)
(prod_{i=1}^n prod_{j=1}^n frac{lcm(i,j)}{gcd(i,j)})
分开得:
[frac{prod_{i=1}^n prod_{j=1}^n ij}{prod_{i=1}^{n}prod_{j=1}^{n}gcd(i,j)^{2}}
]
分子即为((n!)^{2n},)主要方法在分母。
先不看平方,有:
[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]}
]
分解指数:
[sum_{i=1}^n sum_{j=1}^n [gcd(i,j)=d]=sum_{i=1}^{frac{n}{d}}sum_{j=1}^{frac{n}{d}}[gcd(i,j)=1]=sum_{i=1}^{frac{n}{d}}2varphi(i)-1
]
线性出欧拉函数前缀和即可求出。
于是,分母可以枚举指数(O(nlog n))算出。
注意到,模数是质数,所以根据欧拉定理,令指数对(varphi(mod)=mod-1)取模即可免去( ext{long long.})
注意到空间限制,线筛的(vis)数组可以用(bitset.)不要浪费多余空间。减少模的数量,以加快速度。
#include<bits/stdc++.h>
using namespace std;
const int mod=104857601;
const int MAXN=1e6+1;
bitset<MAXN+5>vis;
int p[MAXN+5],phi[MAXN+5],cnt,N,Ans,F,res;
inline int mul(int a,int b){return 1ll*a*b%mod;}
inline int add(int x,int y){return (x+y)%mod;}
void predo(){
phi[1]=1;F=1;int n=N;
for(int i=2;i<=n;++i){
F=1ll*F*i%mod;
if(!vis[i])phi[i]=i-1,p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=n;++j){
vis[i*p[j]]=1;
if(i%p[j]==0){
phi[i*p[j]]=(phi[i]*p[j]);
break;
}
phi[i*p[j]]=(phi[i]*(p[j]-1));
}
}
for(int i=1;i<=n;++i){
phi[i]=phi[i]*2+phi[i-1];
phi[i]%=(mod-1);
}
}
inline int qpow(int a,int b){
res=1;
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);b>>=1LL;
}
return res;
}
int main(){
scanf("%d",&N);
predo();
F=qpow(F,2*N);Ans=1;
for(int i=2;i<=N;++i){Ans=1ll*Ans*qpow(i,phi[N/i]-1)%mod;}
Ans*=1ll;
Ans=mul(Ans,Ans);
Ans=qpow(Ans,mod-2);
Ans=mul(Ans,F);
printf("%lld
",Ans);
return 0;
}