[机房测试] 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);
    }
}
posted @ 2021-11-12 16:43  Kreap  阅读(69)  评论(0编辑  收藏  举报