正题
P5221
题目大意
求 ∏i=1n∏j=1nlcm(i,j)gcd(i,j)\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)}i=1∏nj=1∏ngcd(i,j)lcm(i,j)
解题思路
∏i=1n∏j=1nlcm(i,j)gcd(i,j)\prod_{i=1}^n\prod_{j=1}^n\frac{lcm(i,j)}{gcd(i,j)}i=1∏nj=1∏ngcd(i,j)lcm(i,j)
∏i=1n∏j=1ni×jgcd(i,j)2\prod_{i=1}^n\prod_{j=1}^n\frac{i\times j}{gcd(i,j)^2}i=1∏nj=1∏ngcd(i,j)2i×j
n!2n∏i=1n∏j=1ngcd(i,j)2\frac{n!^{2n}}{\prod_{i=1}^n\prod_{j=1}^ngcd(i,j)^2}∏i=1n∏j=1ngcd(i,j)2n!2n
考虑下面部分如何计算
∏i=1n∏j=1ngcd(i,j)2\prod_{i=1}^n\prod_{j=1}^ngcd(i,j)^2i=1∏nj=1∏ngcd(i,j)2
考虑枚举gcd,然后计算其次数
∏i=1nigi\prod_{i=1}^ni^{g_i}i=1∏nigi
gx=∑i=1n∑j=1n[gcd(i,j)=x]=∑i=1n/x∑j=1n/x[gcd(i,j)=1]=∑i=1n/x∑j=1n/x∑d∣i,d∣jμ(d)=∑d=1n/xμ(d)⌊nxd⌋⌊nxd⌋\begin{aligned} g_x&=\sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)=x]\\ &=\sum_{i=1}^{n/x}\sum_{j=1}^{n/x}[gcd(i,j)=1]\\ &=\sum_{i=1}^{n/x}\sum_{j=1}^{n/x}\sum_{d|i,d|j}\mu(d)\\ &=\sum_{d=1}^{n/x}\mu(d)\left\lfloor\frac{n}{xd}\right\rfloor\left\lfloor\frac{n}{xd}\right\rfloor \end{aligned}gx=i=1∑nj=1∑n[gcd(i,j)=x]=i=1∑n/xj=1∑n/x[gcd(i,j)=1]=i=1∑n/xj=1∑n/xd∣i,d∣j∑μ(d)=d=1∑n/xμ(d)⌊xdn⌋⌊xdn⌋
这个 g 可以整除分块 o(n)o(\sqrt{n})o(n) 求
可以发现,g 只和 n/xn/xn/x 有关,而 n/xn/xn/x 只有 n\sqrt{n}n 个取值,所以可以整除分块(注意这里要把同一个块的数乘起来,然后一起做快速幂,如果一个数单独做的话是 O(nlogn)O(n\ log\ n)O(n log n) 的)
时间复杂度 O(n)O(n)O(n)
code
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 1000100
#define mod 104857601
using namespace std;
int n,w,mu[N],prime[80000];
bool p[N];
ll g,ans,num,sum;
ll pw(ll x,ll y)
{ll z=1;while(y){if(y&1)z=z*x%mod;x=x*x%mod;y>>=1;}return z;
}
void pre_work()
{mu[1]=1;for(int i=2;i<=n;++i){if(!p[i])prime[++w]=i,mu[i]=-1;for(int j=1;j<=w&&i*prime[j]<=n;++j){p[i*prime[j]]=1;if(i%prime[j]==0)break;else mu[i*prime[j]]=-mu[i];}mu[i]+=mu[i-1];}return;
}
ll ask(int n)
{sum=0;for(int l=1,r=0;l<=n;l=r+1){r=n/(n/l);sum=(sum+1ll*(mu[r]-mu[l-1]+mod-1)*(n/l)%(mod-1)*(n/l)%(mod-1))%(mod-1);}return sum;
}
void solve()
{ans=num=1;for(int l=1,r=0;l<=n;l=r+1){r=n/(n/l);g=1;for(int j=l;j<=r;++j)g=g*j%mod;num=num*g%mod;ans=ans*pw(g,ask(n/l))%mod;}return;
}
int main()
{scanf("%d",&n);pre_work();solve();printf("%lld",pw(num,2*n)*pw(1ll*ans*ans%mod,mod-2)%mod);return 0;
}