Loading

【题解】Luogu-P5518 MtOI 2019 幽灵乐团

Page Views Count

莫比乌斯反演练习题

\(\mathrm{lcm}\) 拆成 \(\gcd\),这样实际上要求的就是两个部分,分别是:

\[\prod_{i=1}^A\prod_{j=1}^B\prod_{k=1}^Ci^{f(type)} \]

以及

\[\prod_{i=1}^A\prod_{j=1}^B\prod_{k=1}^C\gcd(i,j)^{f(type)} \]

注意第二个部分要取倒数。

\(type=0\)

第一个部分就是 \((A!)^{BC}\),计算第二个部分。

先枚举 \(\gcd\) 的值,简单推导:

\[\begin{aligned} &\prod_{i=1}^A\prod_{j=1}^B \gcd(i,j)^C\\ =&\prod_{l=1}^A l^{C\sum_{i=1}^A\sum_{j=1}^B [\gcd(i,j)=l]}\\ =&\prod_{l=1}^Al^{C\sum_{i=1}^{\left\lfloor A/l\right\rfloor}\sum_{j=1}^{\left\lfloor B/l\right\rfloor}\sum_{d\mid\gcd(i,j)}\mu(d)}\\ =&\prod_{l=1}^Al^{C\sum_{d=1}^{\left\lfloor A/l\right\rfloor}\mu(d)\times \left\lfloor A/ld \right\rfloor\times \left\lfloor B/ld\right\rfloor}\\ =&\prod_{T=1}^A\prod_{l\mid T} l^{\mu(T/l)\times \left\lfloor A/T\right\rfloor\times \left\lfloor B/T\right\rfloor \times C} \end{aligned}\]

预处理出 \(f(T)=\prod_{l\mid T} l^{\mu(T/l)}\) 就可以数论分块 \(O(\sqrt{n}\log p)\) 解决。

可以讨论一下如何快速预处理出 \(f\),可以写成 \(f(T)=\prod_{l\mid T} \left(\frac{T}{l}\right)^{\mu(l)}\),而分母提出是 \(T^{\sum_{l\mid T}\mu(l)}=1\)

接下来考虑分子,设 \(T'=\prod_{p\mid T,p\in \mathbf{P}} p\),容易发现二者值相同,那么对于每个质数单独考虑,其作为底数出现的所有项中,次数和应当是 \(\mu(p)\sum \mu\left(\frac{l}{p}\right)\),和式的结果当且仅当 \(l=p\) 时为 \(1\) 否则为 \(0\),于是当 \(T\) 只含一个质因子 \(p\) 时,\(f(T)=p\),反之为 \(f(T)=1\)

预处理的复杂度是 \(O(n)\)

\(type=1\)

第一部分:

\[\prod_{i=1}^A\prod_{j=1}^B\prod_{k=1}^C i^{ijk}=\left(\prod_{i=1}^A i^i\right)^{\frac{B(B+1)}{2}\times \frac{C(C+1)}{2}} \]

第二部分也是比较套路的:

\[\begin{aligned} &\prod_{i=1}^A\prod_{j=1}^B\prod_{k=1}^C \gcd(i,j)^{ijk}\\ =&\prod_{i=1}^A\prod_{j=1}^B\gcd(i,j)^{ij\times \frac{C(C+1)}{2}}\\ =&\prod_{l=1}^Al^{\sum_{i=1}^A\sum_{j=1}^B ij\times \frac{C(C+1)}{2} [\gcd(i,j)=l]}\\ =&\prod_{l=1}^{A}l^{\sum_{d=1}^{\left\lfloor A/l\right\rfloor}\mu(d)\times (ld)^2\times \frac{\left\lfloor A/ld\right\rfloor(\left\lfloor A/ld\right\rfloor+1)}{2}\times \frac{\left\lfloor B/ld\right\rfloor(\left\lfloor B/ld\right\rfloor+1)}{2}\times \frac{C(C+1)}{2}}\\ =&\prod_{T=1}^A \prod_{l\mid T} l^{\mu(T/l)\times T^2\times \frac{\left\lfloor A/T\right\rfloor(\left\lfloor A/T\right\rfloor+1)}{2}\times \frac{\left\lfloor B/T\right\rfloor(\left\lfloor B/T\right\rfloor+1)}{2}\times \frac{C(C+1)}{2}} \end{aligned} \]

这部分只能 \(O(n\log n)\) 预处理 \(g(T)=\prod_{l\mid T}l^{\mu(T/l)\times T^2}\)

单词询问依旧是数论分块。

\(type=2\)

第一部分也不好算。

常规的式子写出是:

\[\prod_{i=1}^A i^{\sum_{l\mid i} l\sum_{j=1}^B\sum_{k=1}^C[\gcd(i,j,k)=l]} \]

这个 \(l\mid i\) 的限制不是很友好,可以尝试枚举 \(l\) 的倍数:

\[\begin{aligned} &\prod_{l=1}^A\prod_{i=1}^{\left\lfloor A/l\right\rfloor} (il)^{l\sum_{j=1}^{\left\lfloor B/l\right\rfloor}\sum_{k=1}^{\left\lfloor C/l\right\rfloor} [\gcd(i,j,k)=1]}\\ =&\prod_{l=1}^A\prod_{i=1}^{\left\lfloor A/l\right\rfloor} (il)^{l\sum_{j=1}^{\left\lfloor B/l\right\rfloor}\sum_{k=1}^{\left\lfloor C/l\right\rfloor} \sum_{d\mid \gcd(i,j,k)} \mu(d)} \end{aligned} \]

这里 \(d\) 有一个 \(d\mid i\) 的限制,不如把 \(d\) 提在前面,然后枚举 \(i\)

\[\begin{aligned} &\prod_{l=1}^A\prod_{d=1}^{\left\lfloor A/l\right\rfloor}\prod_{i=1}^{\left\lfloor A/ld\right\rfloor} (ild)^{l\times \mu(d)\times \left\lfloor B/ld\right\rfloor\times \left\lfloor C/ld\right\rfloor}\\ =&\prod_{T=1}^{A}\prod_{l\mid T}\prod_{i=1}^{\left\lfloor A/T\right\rfloor} (iT)^{l\times \mu(T/l)\times \left\lfloor B/T\right\rfloor\times \left\lfloor C/T\right\rfloor}\\ =&\prod_{T=1}^{A}\prod_{l\mid T} \left(\left\lfloor \dfrac{A}{T}\right\rfloor!\times T^{\left\lfloor A/T\right\rfloor}\right)^{l\times \mu(T/l)\times \left\lfloor B/T\right\rfloor\times \left\lfloor C/T\right\rfloor} \end{aligned} \]

这个时候底数和 \(l\) 无关了,指数是 \(\sum_{l\mid T} l\times \mu\left(\frac{T}{l}\right)\times \left\lfloor \frac{B}{T}\right\rfloor\times \left\lfloor \frac{C}{T}\right\rfloor\),注意到 \(\mu * \mathrm{Id}=\varphi\),所以可以化成:

\[\prod_{T=1}^A \left(\left\lfloor \dfrac{A}{T}\right\rfloor!\times T^{\left\lfloor A/T\right\rfloor}\right)^{\varphi(T)\times \left\lfloor B/T\right\rfloor\times \left\lfloor C/T\right\rfloor} \]

预处理 \(\varphi\) 的前缀和以及 \(T^{\varphi(T)}\) 的前缀积即可。

第二部分可以枚举 \(\gcd(i,j)\)\(\gcd(i,j,k)\)

\[\begin{aligned} &\prod_{l=1}^{A}\prod_{i=1}^{A}\prod_{j=1}^B \gcd(i,j)^{l\sum_{k=1}^{C} [\gcd(i,j,k)=l]}\\ =&\prod_{l=1}^{A}\prod_{i=1}^{\left\lfloor A/l\right\rfloor}\prod_{j=1}^{\left\lfloor B/l\right\rfloor} (\gcd(i,j)\times l)^{l\sum_{k=1}^{\left\lfloor C/l\right\rfloor} [\gcd(i,j,k)=1]}\\ =&\prod_{l=1}^A\prod_{d=1}^{\left\lfloor A/l\right\rfloor}\prod_{i=1}^{\left\lfloor A/ld\right\rfloor}\prod_{j=1}^{\left\lfloor B/ld\right\rfloor}(\gcd(i,j)\times ld)^{l\times \mu(d)\times \left\lfloor C/ld\right\rfloor}\\ =&\prod_{T=1}^A\prod_{l\mid T}\prod_{i=1}^{\left\lfloor A/T\right\rfloor}\prod_{j=1}^{\left\lfloor B/T\right\rfloor}(\gcd(i,j)\times T)^{l\times \mu(T/l)\times \left\lfloor C/T\right\rfloor}\\ =&\prod_{T=1}^{A}\prod_{i=1}^{\left\lfloor A/T\right\rfloor}\prod_{j=1}^{\left\lfloor B/T\right\rfloor}(\gcd(i,j)\times T)^{\varphi(T)\times \left\lfloor C/T\right\rfloor} \end{aligned} \]

底数拆成两部分,\(T\) 的一部分是 \(\prod_{T=1}^{A} T^{\varphi(T)\times \left\lfloor A/T\right\rfloor\times \left\lfloor B/T\right\rfloor\times \left\lfloor C/T\right\rfloor}\),正常分块即可。

\(\gcd(i,j)\) 的部分要再推一下,常规处理就可以:

\[\prod_{i=1}^{\left\lfloor A/T\right\rfloor}\prod_{j=1}^{\left\lfloor B/T\right\rfloor} \gcd(i,j)=\prod_{T'=1}^{\left\lfloor A/T\right\rfloor} \prod_{l\mid T'} l^{\mu(T'/l)\times \left\lfloor A/TT'\right\rfloor\times \left\lfloor B/TT'\right\rfloor}\]

还是上面的 \(f(T)\) 函数,注意到要对 \(T\) 做一次数论分块,内部要对 \(T'\) 再做一次,两次数论分块的复杂度是 \(O(n^{3/4})\)

复杂度分析同一次分块类似,设第一次枚举到的值为 \(i\),那么第二次分块的复杂度是 \(O\left(\sqrt{\left\lfloor\frac{n}{i}\right\rfloor}\right)\)

\(i>\sqrt{n}\) 时,有 \(O(\sqrt{n})\) 个块,每个块大小不超过 \(\sqrt{n}\),所以复杂度 \(O(n^{3/4})\)

\(i\le \sqrt{n}\) 时,可以列出式子:

\[\begin{aligned} &O\left(\sum_{i=1}^{\sqrt{n}}\sqrt{\left\lfloor\dfrac{n}{i}\right\rfloor}\right)\\ =&O\left(\sum_{i=1}^{\sqrt{n}}\sqrt{\dfrac{n}{i}}\right)\\ =&O\left(\sqrt{n}\int_{1}^{\sqrt{n}} \dfrac{1}{\sqrt{x}} \mathrm{d}x\right) \end{aligned} \]

\(\frac{1}{\sqrt{x}}\)\(2\sqrt{x}\) 的导数,所以定积分是 \(2(n^{1/4}-1)\),这样分析到了 \(O(n^{3/4})\) 的复杂度。

于是整体复杂度就是 \(O(n\log p+Tn^{3/4}\log p)\)

点击查看代码
inline int q_pow(int A,int B,int P){
    int res=1;
    while(B){
        if(B&1) res=1ll*res*A%P;
        A=1ll*A*A%P;
        B>>=1;
    }
    return res;
}

int T;
int mod,inv2;
int fact[maxn],prodpw[maxn];
int pr[maxn],mn[maxn],mu[maxn],sumphi[maxn],prodpwphi[maxn];
int f1[maxn],invf1[maxn],f2[maxn],pw[maxn],inv_pw[maxn],f3[maxn];
bool vis[maxn];

inline void linear_sieve(){
    mu[1]=1,sumphi[1]=1,f1[1]=1;
    for(int i=2;i<=lim;++i){
        if(!vis[i]) pr[++pr[0]]=i,mn[i]=i,mu[i]=-1,sumphi[i]=i-1,f1[i]=i;
        for(int j=1;j<=pr[0]&&i*pr[j]<=lim;++j){
            vis[i*pr[j]]=1,mn[i*pr[j]]=pr[j],mu[i*pr[j]]=-mu[i];
            if(mn[i]==pr[j]) sumphi[i*pr[j]]=sumphi[i]*pr[j],f1[i*pr[j]]=f1[i];
            else sumphi[i*pr[j]]=sumphi[i]*sumphi[pr[j]],f1[i*pr[j]]=1;
            if(i%pr[j]==0){
                mu[i*pr[j]]=0;
                break;
            }
        }
    }
    prodpwphi[0]=1;
    for(int i=1;i<=lim;++i) prodpwphi[i]=1ll*prodpwphi[i-1]*q_pow(i,sumphi[i],mod)%mod;
    for(int i=1;i<=lim;++i) sumphi[i]=(sumphi[i-1]+sumphi[i])%(mod-1);
    for(int i=1;i<=lim;++i) f2[i]=q_pow(f1[i],1ll*i*i%(mod-1),mod);
    f1[0]=1;
    for(int i=1;i<=lim;++i) f1[i]=1ll*f1[i-1]*f1[i]%mod;
    for(int i=0;i<=lim;++i) invf1[i]=q_pow(f1[i],mod-2,mod);
    f2[0]=1;
    for(int i=1;i<=lim;++i) f2[i]=1ll*f2[i-1]*f2[i]%mod;
    for(int i=1;i<=lim;++i){
        pw[i]=q_pow(i,i,mod),inv_pw[i]=q_pow(pw[i],mod-2,mod);
        f3[i]=1;
    }
    for(int i=1;i<=lim;++i){
        for(int j=1;i*j<=lim;++j){
            if(mu[j]==1) f3[i*j]=1ll*f3[i*j]*pw[i]%mod;
            if(mu[j]==-1) f3[i*j]=1ll*f3[i*j]*inv_pw[i]%mod;
        }
    }
    f3[0]=1;
    for(int i=1;i<=lim;++i) f3[i]=1ll*f3[i-1]*f3[i]%mod;
    fact[0]=1;
    for(int i=1;i<=lim;++i) fact[i]=1ll*fact[i-1]*i%mod;
    prodpw[0]=1;
    for(int i=1;i<=lim;++i) prodpw[i]=1ll*prodpw[i-1]*q_pow(i,i,mod)%mod;
}

inline int calc1(int A,int B,int C){
    return q_pow(fact[A],1ll*B*C%(mod-1),mod);
}
inline int calc2(int A,int B,int C){
    int res=1;
    if(A>B) swap(A,B);
    for(int l=1,r;l<=A;l=r+1){
        r=min(A/(A/l),B/(B/l));
        int now=1ll*f1[r]*invf1[l-1]%mod;
        now=q_pow(now,1ll*C*(A/l)%(mod-1)*(B/l)%(mod-1),mod);
        res=1ll*res*now%mod;
    } 
    res=q_pow(res,mod-2,mod);
    return res;
}
inline void solve0(int A,int B,int C){
    int res;
    res=1ll*calc1(A,B,C)*calc1(B,A,C)%mod;
    res=1ll*res*calc2(A,B,C)%mod*calc2(A,C,B)%mod;
    printf("%d ",res);
}

inline int calc3(int A,int B,int C){
    int e1=1ll*B*(B+1)/2%(mod-1),e2=1ll*C*(C+1)/2%(mod-1);
    return q_pow(prodpw[A],1ll*e1*e2%(mod-1),mod);
}
inline int calc4(int A,int B,int C){
    int res=1;
    if(A>B) swap(A,B);
    for(int l=1,r;l<=A;l=r+1){
        r=min(A/(A/l),B/(B/l));
        int now=1ll*f2[r]*q_pow(f2[l-1],mod-2,mod)%mod;
        int e1=1ll*(A/l)*(A/l+1)/2%(mod-1),e2=1ll*(B/l)*(B/l+1)/2%(mod-1),e3=1ll*C*(C+1)/2%(mod-1);
        now=q_pow(now,1ll*e1*e2%(mod-1)*e3%(mod-1),mod);
        res=1ll*res*now%mod;
    }
    res=q_pow(res,mod-2,mod);
    return res;
}
inline void solve1(int A,int B,int C){
    int res;
    res=1ll*calc3(A,B,C)*calc3(B,A,C)%mod;
    res=1ll*res*calc4(A,B,C)%mod*calc4(A,C,B)%mod;
    printf("%d ",res);
}

inline int calc5(int A,int B,int C){
    int res=1;
    for(int l=1,r;l<=min({A,B,C});l=r+1){
        r=min({A/(A/l),B/(B/l),C/(C/l)});
        int now=q_pow(fact[A/l],(sumphi[r]-sumphi[l-1]+mod-1)%(mod-1),mod);
        now=1ll*now*q_pow(1ll*prodpwphi[r]*q_pow(prodpwphi[l-1],mod-2,mod)%mod,A/l,mod)%mod;
        now=q_pow(now,1ll*(B/l)*(C/l)%(mod-1),mod)%mod;
        res=1ll*res*now%mod;
    }
    return res;
}
inline int calc6(int A,int B,int C){
    int res=1;
    if(A>B) swap(A,B);
    for(int l=1,r;l<=min({A,B,C});l=r+1){
        r=min({A/(A/l),B/(B/l),C/(C/l)});
        int now=1ll*prodpwphi[r]*q_pow(prodpwphi[l-1],mod-2,mod)%mod;
        now=q_pow(now,1ll*(A/l)*(B/l)%(mod-1)*(C/l)%(mod-1),mod);
        res=1ll*res*now%mod;
    }
    int cnt=1;
    for(int l1=1,r1;l1<=min({A,B,C});l1=r1+1){
        r1=min({A/(A/l1),B/(B/l1),C/(C/l1)});
        int now1=1;
        for(int l2=1,r2;l2<=min(A/l1,B/l1);l2=r2+1){
            ++cnt;
            r2=min((A/l1)/(A/l1/l2),(B/l1)/(B/l1/l2));
            int now2=1ll*f1[r2]*invf1[l2-1]%mod;
            now2=q_pow(now2,1ll*(A/l1/l2)*(B/l1/l2)%(mod-1),mod);
            now1=1ll*now1*now2%mod;
        }
        now1=q_pow(now1,1ll*(sumphi[r1]-sumphi[l1-1]+mod-1)%(mod-1)*(C/l1)%(mod-1),mod);
        res=1ll*res*now1%mod;
    }
    res=q_pow(res,mod-2,mod);
    cerr<<cnt<<endl;
    return res;
}
inline void solve2(int A,int B,int C){
    int res=1;
    res=1ll*calc5(A,B,C)*calc5(B,A,C)%mod;
    res=1ll*res*calc6(A,B,C)%mod*calc6(A,C,B)%mod;
    printf("%d\n",res);
}

int A,B,C;

int main(){
    T=read(),mod=read();
    linear_sieve();
    while(T--){
        A=read(),B=read(),C=read();
        solve0(A,B,C);
        solve1(A,B,C);
        solve2(A,B,C);
    }
    return 0;
}
posted @ 2023-05-17 18:17  SoyTony  阅读(52)  评论(2编辑  收藏  举报