P5518 [MtOI2019]幽灵乐团 / 莫比乌斯反演基础练习题
-
P5518 [MtOI2019]幽灵乐团 / 莫比乌斯反演基础练习题
看完数据范围(\(T=70\))大概是对于每个 \(type\) 做到 \(O(n)\) 以内。
type=0
\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\dfrac{\operatorname{lcm(i,j)}}{\gcd(i,k)}\\ =\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\dfrac{i\times j}{\gcd(i,j)\times \gcd(i,k)}\\ \]分母:
\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\gcd(i,j)\\ =(\prod_{d=1}^{A}d^{\sum_{i=1}^{A}\sum_{j=1}^{B}[\gcd(i,j)==d]})^C\\ =(\prod_{d=1}^{A}d^{f(\frac{n}{d},\frac{m}{d})})^C \]其中
\[f(n,m)=\sum_{i=1}^{n} \sum_{j=1}^{m}[gcd(i,j)==1]\\ =\sum_{x=1}^{n}\mu(x)\frac{n}{x}\dfrac{m}{x} \]\(2\) 层整除分块就可以 \(O(n+\sqrt{n}\log n)\) 了。
分子:
\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}ij\\ =(\prod_{i=1}^{A}\prod_{j=1}^{B}ij)^C\\ =((A!)^{B}\times(B!)^{A})^C \]预处理阶乘可 \(O(\log n)\) 计算。
type=1
\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}(\dfrac{i\times j}{\gcd(i,j)\times \gcd(i,k)})^{ijk}\\ \]分子:
\[\prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}(ij)^{ijk}\\ =(\prod_{i=1}^{A}(i^i)^{1+2+\cdots A}\prod_{j=1}^{B}(j^j)^{1+2+\cdots+A})^{1+2+\cdots+C}\\ \]令 \(jp_n=\prod_{i=1}^{n}i^i\) (快速幂预处理),则原式
\[=((jp_A)^{1+2+\cdots+B}(jp_B)^{1+2+\cdots+A})^{1+2+\cdots+C}\\ =((jp_A)^{B\times(B+1)/2} \times (jp_B)^{A\times(A+1)/2})^{C\times(C+1)/2} \]分母:
\[\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})^{C\times(C+1)/2}\\ =(\prod_{d=1}^{A}d^{f(A,B,d)})^{C\times(C+1)/2}\\ \]其中
\[f(n,m,d)=\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)==d]ij\\ =d^2\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[\gcd(i,j)==1]ij\\ =d^2\sum_{x=1}^{\frac{n}{d}}\mu(x)x^2\sum_{i=1}^{\frac{n}{dx}}\sum_{j=1}^{\frac{m}{dx}}ij\\ \]带回原式换个写法
其中
快速幂预处理 \(d^{(d^2)}\) 就可以整除分块套整除分块 \(O(n)\) 了
type=2
请确认您掌握狄利克雷卷积,这部分大量运用狄利克雷卷积来化简式子
分子:
注意到指数有一个 \(\sum_{d|T}\mu(\dfrac{T}{d})d=\mu*I=\varphi\)
预处理 \(T^{\varphi(T)}\) 的前缀积和 \(\sum\varphi(i) \% (mod-1)\) 整除分块即可。
分母:
单独提出后一部分来算。
带回去
\(x|d|T\) 连着整除好奇怪。。。
考虑到 \(d=x\cdot \dfrac{d}{x}\) ,分成 \(2\) 部分算
部分一
\(O(n\log n)\) 预处理 \(d^{\mu(\frac{T}{d})}\) 外边两层整除分块即可 \(O(n)\)
小优化:\(\mu(x)\) 非零的个数并不多,实测 \(10000\) 不到一点,虽然有个 \(\log\) ,合起来近似 \(O(n)\) ,判一下 \(\mu\) 的值可以快一点。
部分二
\(\sum_{d|T}\mu(\dfrac{T}{d})=\mu*I=\epsilon\)
所以只用计算 \(T=1\) 时的情形即可
整除分块就够了!
注意事项
-
指数取模要模 \(mod-1\)
-
long long
别少开,1ll
别少乘 -
整除分块内层要快速幂的时候预处理逆元,否则单次询问变成 \(O(n\log n)\)
心力憔悴啊,毒瘤。
提供一组大样例以供调试
Input
3 998244353
6 6 6
100000 100000 100000
99998 99999 100000
Output
570465346 682784945 524427235
862376103 371412326 358248208
103815203 127873959 745848036
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N=100005;
int T,mod,A,B,C,iv6;
int mu[N],pri[N/9],cnt,jc[N],jp[N],sm[N],jk[N],st[N],phi[N],fp[N],vf[N];
bool vis[N];
int qpow(int n,int k,int res=1){
for(;k;k>>=1,n=1ll*n*n%mod)
if(k&1)res=1ll*n*res%mod;
return res;
}
void Sieve(const int N=100000){
mu[1]=1,phi[1]=1,jc[0]=1,jp[0]=1,jk[0]=1,st[0]=1,fp[0]=1,fp[1]=1,vf[0]=1;
for(int i=2;i<=N;++i){
fp[i]=1;
if(!vis[i])pri[++cnt]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=cnt&&i*pri[j]<=N;++j){
vis[i*pri[j]]=1;
if(i%pri[j]==0){phi[i*pri[j]]=phi[i]*pri[j];break;}
mu[i*pri[j]]=-mu[i],phi[i*pri[j]]=phi[i]*phi[pri[j]];
}
}
for(int i=1;i<=N;++i){
if(!mu[i])continue;
for(int j=1;i*j<=N;++j)
if(mu[i]==1)fp[i*j]=1ll*fp[i*j]*j%mod;
else fp[i*j]=1ll*fp[i*j]*qpow(j,mod-2)%mod;
}
for(int i=1;i<=N;++i)fp[i]=1ll*fp[i]*fp[i-1]%mod,vf[i]=qpow(fp[i],mod-2);
for(int i=1;i<=N;++i)
jc[i]=1ll*jc[i-1]*i%mod,
jp[i]=1ll*jp[i-1]*qpow(i,i)%mod,
sm[i]=(sm[i-1]+1ll*mu[i]*i%(mod-1)*i%(mod-1))%(mod-1),
jk[i]=1ll*jk[i-1]*qpow(i,1ll*i*i%(mod-1))%mod,
mu[i]+=mu[i-1],
st[i]=1ll*st[i-1]*qpow(i,phi[i])%mod,
phi[i]=(phi[i]+phi[i-1])%(mod-1);
/*
Attention:
mu:∑μ
jc :阶乘 mod mod
jp : i^i 的前缀积 mod mod
sm:∑μ(x)*x*x mod (mod-1)
jk:∏i^(i^2) mod (mod-1)
phi:∑φ mod (mod-1)
st:πT^phi(T) mod mod
fp:∑π(d|T)d^μ(T/d) mod mod
vf:qpow(fp,mod-2)
*/
}
namespace Task0{
int fz,fm;
int f(int n,int m){
if(n>m)n^=m^=n^=m;
int res=0;
for(int l=1,r;l<=n;l=r+1)
r=min(n/(n/l),m/(m/l)),res=(res+1ll*(n/l)*(m/l)%(mod-1)*(mu[r]-mu[l-1])%(mod-1))%(mod-1);
return (res+mod-1)%(mod-1);
}
int g(int n,int m){
if(n>m)n^=m^=n^=m;
int res=1;
for(int l=1,r;l<=n;l=r+1)
r=min(n/(n/l),m/(m/l)),res=1ll*res*qpow(1ll*jc[r]*qpow(jc[l-1],mod-2)%mod,f(n/l,m/l))%mod;
return (res+mod)%mod;
}
void main(){
fz=qpow(1ll*qpow(jc[A],B)*qpow(jc[B],A)%mod,C)%mod;
fm=qpow(1ll*qpow(g(A,B),C)*qpow(g(A,C),B)%mod,mod-2);
printf("%lld ",1ll*fz*fm%mod);
}
}
namespace Task1{
int fz,fm;
int s(int x,int y){
return (1ll*x*(x+1)/2%(mod-1))*(1ll*y*(y+1)/2%(mod-1))%(mod-1);
}
int s2(int x){
return 1ll*x*(x+1)%mod*(x+x+1)%mod*iv6%mod;
}
int f(int n,int m){
if(n>m)n^=m^=n^=m;
int res=0;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
res=(res+1ll*s(n/l,m/l)*(sm[r]-sm[l-1])%(mod-1))%(mod-1);
}
return (res+mod-1)%(mod-1);
}
int g(int n,int m){
if(n>m)n^=m^=n^=m;
int res=1;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
res=1ll*res*qpow(1ll*jk[r]*qpow(jk[l-1],mod-2)%mod,f(n/l,m/l))%mod;
}
return (res+mod)%mod;
}
void main(){
fz=qpow(1ll*qpow(jp[A],1ll*B*(B+1)/2%(mod-1))*qpow(jp[B],1ll*A*(A+1)/2%(mod-1))%mod,1ll*C*(C+1)/2%(mod-1));
fm=qpow(1ll*qpow(g(A,B),1ll*C*(C+1)/2%(mod-1))*qpow(g(A,C),1ll*B*(B+1)/2%(mod-1))%mod,mod-2);
printf("%lld ",1ll*fz*fm%mod);
}
}
namespace Task2{
int fz,fm;
int f(int A,int B,int C){
int res=1;
for(int l=1,r,mx=min(A,min(B,C));l<=mx;l=r+1){
r=min(A/(A/l),min(B/(B/l),C/(C/l)));
res=1ll*res*qpow(jc[A/l],1ll*(B/l)*(C/l)%(mod-1)*(phi[r]-phi[l-1]+mod-1)%(mod-1))%mod;
res=1ll*res*qpow(1ll*st[r]*qpow(st[l-1],mod-2)%mod,1ll*(A/l)*(B/l)*(C/l)%(mod-1))%mod;
}
return res;
}
int h(int n,int m){
if(n>m)n^=m^=n^=m;
int res=1;
for(int l=1,r;l<=n;l=r+1){
r=min(n/(n/l),m/(m/l));
res=1ll*res*qpow(1ll*fp[r]*vf[l-1]%mod,1ll*(n/l)*(m/l)%(mod-1))%mod;
}
return res;
}
int g(int A,int B,int C){
int res=1;
for(int l=1,r,mx=min(A,min(B,C));l<=mx;l=r+1){
r=min(A/(A/l),min(B/(B/l),C/(C/l)));
res=1ll*res*qpow(1ll*st[r]*qpow(st[l-1],mod-2)%mod,1ll*(A/l)*(B/l)*(C/l)%(mod-1))%mod;
res=1ll*res*qpow(h(A/l,B/l),1ll*(phi[r]-phi[l-1]+mod-1)*(C/l)%(mod-1))%mod;
}
return res;
}
void main(){
fz=1ll*f(A,B,C)*f(B,A,C)%mod;
fm=qpow(1ll*g(A,B,C)*g(A,C,B)%mod,mod-2);
printf("%lld ",1ll*fz*fm%mod);
}
}
signed main(){
T=read(),mod=read(),iv6=qpow(6,mod-2),Sieve();
while(T--) {
A=read(),B=read(),C=read();
Task0::main(),Task1::main(),Task2::main(),puts("");
}
}