[机房测试] Lcm
Description
\(T\leq 10^3\) 次询问,求
\[(*)=\prod_{i_1=1}^n \prod_{i_2=1}^n\dots\prod_{i_k=1}^n \frac{i_1i_2\dots i_k}{\gcd(i_1,i_2,\dots,i_k)}
\]
其中 \(n\leq 3\times 10^5\),\(k\leq 10^{18}\)
Solution
\[(*)=\frac{(n!)^{kn^{k-1}}}{\prod_{d=1}^n d^{f(d)}}
\]
其中 \(f(d)\) 是 \(\gcd=d\) 的方案数。设 \(g(d)\) 表示 \(d|\gcd\) 的方案数,则有
\[\begin{align}
f(d)&=\sum_{d|i} \mu(\frac{i}{d})g(i)\\
g(d)&=\lfloor \frac{n}{d} \rfloor ^k
\end{align}
\]
这样就得到一个 \(O(Tn\log n\log k)\) 的做法。预处理快速幂,可以做到 \(O(Tn\log n)\)。
合并并化简,可以得到
\[f(d)=\sum_{i=1}^{\lfloor \frac{n}{d} \rfloor} \mu(i) \lfloor \frac{\lfloor\frac{n}{d}\rfloor}{i} \rfloor^k
\]
可以发现,\(f(d)\) 只有 \(\sqrt n\) 种取值,\(f(d)\) 的内和也是同理的。运用整除分块嵌套,可以做到 \(O(Tn^{\frac{3}{4}}\log k)\)。
再次观察,有
\[\lfloor \frac{\lfloor\frac{n}{d}\rfloor}{i} \rfloor=\lfloor \frac{n}{id} \rfloor
\]
所以这两个表达式所有取值组成的集合是相同的,预处理所有 \(\lfloor \frac{n}{d} \rfloor\) 的幂,可以做到 \(O(Tn^{\frac{3}{4}})\).
#include<stdio.h>
#include<cassert>
typedef long long ll;
const int N=3e5+7;
const int Mod=998244353;
inline ll read(){
ll x=0,flag=1; char c=getchar();
while(c<'0'||c>'9'){if(c=='-')flag=1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
bool mk[N];
ll fac[N],ifac[N],K,pw[N];
int mu[N],p[N],pn=0,n;
ll qpow(ll x,ll y,int mod){
ll ret=1;
while(y){
if(y&1) ret=ret*x%mod;
x=x*x%mod,y>>=1;
}
return ret;
}
inline ll f(int x){
ll ret=0;
for(int l=1,r=0;l<=x;l=r+1)
r=x/(x/l),ret=(ret+(mu[r]-mu[l-1])*pw[x/l]%(Mod-1)+(Mod-1))%(Mod-1);
return ret;
}
int main(){
int T=read(); fac[0]=1,mu[1]=1;
for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%Mod;
ifac[N-1]=qpow(fac[N-1],Mod-2,Mod);
for(int i=N-2;~i;i--) ifac[i]=ifac[i+1]*(i+1)%Mod;
for(int i=2;i<N;i++){
if(!mk[i]) p[++pn]=i,mu[i]=-1;
for(int j=1;j<=pn&&p[j]*i<N;j++){
mk[p[j]*i]=1; if(i%p[j]==0) break;
mu[p[j]*i]=-mu[i];
}
}
for(int i=2;i<N;i++) mu[i]+=mu[i-1];
while(T--){
n=read(); K=read();
ll ans=qpow(fac[n],(K%(Mod-1))*qpow(n,K-1,Mod-1)%(Mod-1),Mod),ret=1;
for(int l=1,r=0;l<=n;l=r+1)
r=n/(n/l),pw[n/l]=qpow(n/l,K,Mod-1);
for(int l=1,r=0;l<=n;l=r+1)
r=n/(n/l),ret=ret*qpow(fac[r]*ifac[l-1]%Mod,f(n/l),Mod)%Mod;
printf("%lld\n",ans*qpow(ret,Mod-2,Mod)%Mod);
}
}