1. 程式人生 > 實用技巧 >【題解】Product

【題解】Product

\(\color{brown}{Link}\)

\(\text{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}}2\varphi(i)-1 \]

線性出尤拉函式字首和即可求出。

於是,分母可以列舉指數\(O(n\log n)\)算出。

注意到,模數是質數,所以根據尤拉定理,令指數對\(\varphi(mod)=mod-1\)取模即可免去\(\text{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\n",Ans);
	return 0;
}