Luogu5221

Update

  • 2021-02-07 这篇题解已经拖了半年了,现在开始写.

原式 \(=\prod\limits_{i=1}^n\prod\limits_{j=1}^n\dfrac{ij}{(\gcd\{i,j\})^2}=\dfrac{\prod\limits_{i=1}^n\prod\limits_{j=1}^nij}{(\prod\limits_{i=1}^n\prod\limits_{j=1}^n\gcd\{i,j\})^2}\)

对分数线上面那个柿子,

\[\prod_{i=1}^n\prod_{j=1}^nij=\prod_{i=1}^ni^nn!=(\prod_{i=1}^ni^n)(\prod_{i=1}^nn!)=(n!)^{2n} \]

因此只要处理好分数线下面那个柿子,配合一个逆元即可.


由唯一分解定理我们知道:

\[n=\prod_{p\in P} p^a\ \ \ (a\ge0,P\ includes\ all\ the\ prime\ that's\ not\ more\ than\ n) \]

因此

\[\prod_{i=1}^n\prod_{j=1}^n\gcd\{i,j\}=\prod_{p\in P}p^{\sum\limits_k\sum\limits_{i=1}^n\sum\limits_{j=1}^n[p^k\mid \gcd\{i,j\}]}=\prod_{p\in P}p^{\sum\limits_{k=1}^{\left\lfloor\log_pn\right\rfloor}\left\lfloor\frac{n}{p^k}\right\rfloor^2} \]

对这个柿子暴力即可.


复杂度分析

分数线上面那个柿子 \(O(n)\) 求阶乘配合一个快速幂即可.

下面这个柿子,首先跑一遍欧拉质数筛(\(O(n)\) 线性筛).

指数上那个柿子,可以 \(O(\log n)\) 跑暴力,其值可以证明是不高于 \(n^2\) 的,因此快速幂也是 \(O(\log n)\) 的.

\(1\)\(n\) 的质数个数为 \(\pi(n)\),则下面这个柿子的计算总复杂度应该是 \(O(\pi(n)\log n)\)?

我们知道一个柿子,

\[\pi(n)\approx\dfrac n{\ln n} \]

因此下面这个柿子的复杂度可以看做是 \(O(n)\) 的!

逆元的复杂度并不高, 因此合并俩柿子后的总复杂度是 \(O(n)\) 的!


code:

#include <math.h>
#include <stdio.h>
#include <vector>
typedef long long llt;
typedef unsigned uint;typedef unsigned long long ullt;
typedef bool bol;typedef char chr;typedef void voi;
template<typename T>
std::vector<T>Euler_prime(T num,bol*S)//素数欧氏筛
{
	std::vector<T>Ans;T len=0;Ans.clear();
	for(T i=2;i<=num;i++)S[i]=true;if(num)S[0]=S[1]=false;
	for(T i=2;i<=num;i++)
	{
		if(S[i])Ans.push_back(i),len++;
		for(T j=0;j<len;j++)
		{
			if(Ans[j]*i>num)break;S[i*Ans[j]]=false;if(!(i%Ans[j]))break;
		}
	}
	return Ans;
}
template<typename T>
T power_user(T base,T index,T mod)
{
    T p=(index&1)?base:1,ans;if(mod)p%=mod;
    if(index<=1)return p;
    ans=power_user(base,index>>1,mod);
    ans*=ans;if(mod)ans%=mod;
    ans*=p;if(mod)ans%=mod;
    return ans;
}
template<typename T>
T power(T base,T index,T mod)
{
    if(mod==1)return 0;
    if(!index||base==1||(mod&&base%mod==1))return mod?(1%mod):1;
    if(!base||(mod&&!(base%mod)))return 0;
    return power_user(mod?base%mod:base,index,mod);
}
const ullt Mod=104857601;
std::vector<uint>P;bol B[1000010];
int main()
{
	uint n;ullt p,q,ans=1;scanf("%u",&n),P=Euler_prime(n,B);
	for(std::vector<uint>::iterator iter=P.begin();iter!=P.end();iter++)
	{
	    p=0,q=*iter;while(q<=n)p+=(n/q)*(n/q),p%=Mod-1,q*=*iter;ans*=power<ullt>(*iter,p,Mod),ans%=Mod;
    }
    ans*=ans,ans%=Mod,ans=power(ans,Mod-2,Mod),p=1;
    for(uint i=2;i<=n;i++)p*=i,p%=Mod;ans*=power<ullt>(p,n<<1,Mod),ans%=Mod;
    printf("%llu\n",ans);
	return 0;
}

码风谔谔,请多见谅.


END

posted @ 2022-02-14 06:58  myee  阅读(30)  评论(0)    收藏  举报