题目大意
\(T\) 组数据,每组数据给定 \(A,B,C\),求:
其中,\(type \in \{0,1,2\}\),\(f(0)=1,f(1)=i\times j\times k,f(2)=\gcd(i,j,k)\)。
思路分析
神经污染题,三合一大礼包。
首先简单化一下式子:
设三元函数 \(f_1(a,b,c)=\prod_{i=1}^a\prod_{j=1}^b\prod_{k=1}^ci^{f(type)}\),\(f_2(a,b,c)=\prod_{i=1}^a\prod_{j=1}^b\prod_{k=1}^c\gcd(i,j)^{f(type)}\),则原式可化为
现在的问题就变成了如何计算 \(f_1\) 和 \(f_2\)。
- \(type=0\)
此时 \(f_1(a,b,c)=\prod_{i=1}^a\prod_{j=1}^b\prod_{k=1}^ci=(a!)^{bc}\),预处理阶乘后直接用快速幂计算即可。
考虑 \(f_2\),有
括号里是一个经典式子,简单化一下:
中间部分可以直接 \(O(n\ln n)\) 枚举倍数预处理出来,然后再整除分块就可以做到 \(O(\sqrt n\log n)\) 回答询问。
- \(type=1\)
先考虑 \(f_1\),此时有:
设 \(S(x)=\frac{x(x+1)}{2}\),则
括号里面的部分可以暴力 \(O(n\log n)\) 预处理出来,\(O(\log n)\) 回答询问。
再看 \(f_2\),此时有:
中间的部分也可以 \(O(n\ln n)\) 预处理出来,依旧是 \(O(\sqrt n\log n)\) 回答单次询问。
- \(type=2\)
先看 \(f_1\):
先别急着看能不能做(做是肯定能做的,预处理 \(T^{\varphi(T)}\) 和 \(\varphi\) 的前缀和就可以了),推最后一个式子(也是最难推的式子):
将 \(f_1\) 和 \(f_2\) 同时消去左边部分,得
此时 \(f_1'\) 容易计算,继续推 \(f_2\):
对比中间部分和 \(type=0\) 时 \(f_2\) 的中间部分的形式,得
中间部分按照类似计算 \(type=0\) 时 \(f_2\) 的计算方式计算,再套一个整除分块,可以做到 \(O(n^{\frac{3}{4}}\log n)\) 回答单次询问。
故总时间复杂度是 \(O(n\log n+Tn^{\frac{3}{4}}\log n)\)。
思路总结
- 预处理:
阶乘,欧拉函数,欧拉函数前缀和,莫比乌斯函数,\(g_1(n)=\prod_{d|n}d^{\mu(\frac{n}{d})}\),\(g_2(n)=\prod_{i=1}^ni^i\),\(g_3(n)=\prod_{d|n}d^{\mu(\frac{n}{d})n^2}\),\(g_1\) 的前缀积和前缀积的逆元,\(g_3\) 的前缀积和前缀积的逆元。
- \(type=0\)
分子用阶乘和快速幂算,分母用整除分块和 \(g_1\) 的前缀积算。
- \(type=1\)
算分子用到 \(g_2\) 和快速幂,算分母的整除分块用到 \(g_3\) 的前缀积。
- \(type=2\)
用到阶乘和欧拉函数的前缀和,整除分块算分子。
分母用到整除分块套整除分块,其中外层用到欧拉函数的前缀和,内层与 \(type=0\) 时的整除分块相同。
代码
(这绝对是我到目前为止打过的最长的数论题的代码了)
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=100100,L=100000;
typedef long long ll;
#define S2(n) ((1ll*n*(n+1)/2)%mod1)
int mod,mod1,T,A,B,C,cnt;
int prime[N],v[N],mu[N],phi[N];
ll fac[N],dmuTd[N],ii[N],Sphi[N];
ll PdmuTd[N],invPdmuTd[N];
ll PdmuTdTT[N],invPdmuTdTT[N];
ll q_pow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
void init(){
phi[1]=mu[1]=fac[0]=fac[1]=1;
Sphi[1]=dmuTd[1]=ii[0]=1;
PdmuTd[0]=invPdmuTd[0]=1;
PdmuTdTT[0]=invPdmuTdTT[0]=1;
for(int i=2;i<=L;i++){
if(!v[i]){
prime[++cnt]=i;
mu[i]=-1;
phi[i]=i-1;
}
for(int j=1;j<=cnt&&i*prime[j]<=L;j++){
v[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*phi[prime[j]];
mu[i*prime[j]]=-mu[i];
}
dmuTd[i]=1;
fac[i]=fac[i-1]*i%mod;
Sphi[i]=Sphi[i-1]+phi[i];
}
for(int i=1;i<=L;i++){
ii[i]=ii[i-1]*q_pow(i,i)%mod;
for(int j=i;j<=L;j+=i){
if(mu[i]==1) dmuTd[j]=dmuTd[j]*(j/i)%mod;
if(mu[i]==-1) dmuTd[j]=dmuTd[j]*q_pow(j/i,mod-2)%mod;
}
}
for(int i=1;i<=L;i++){
PdmuTd[i]=PdmuTd[i-1]*dmuTd[i]%mod;
invPdmuTd[i]=q_pow(PdmuTd[i],mod-2);
PdmuTdTT[i]=PdmuTdTT[i-1]*q_pow(dmuTd[i],1ll*i*i%mod1)%mod;
invPdmuTdTT[i]=q_pow(PdmuTdTT[i],mod-2);
}
}
ll TYPE0_solve(int A,int B){
int M=min(A,B);
ll res=1;
for(int l=1,r;l<=M;l=r+1){
int Al=A/l,Bl=B/l;
r=min(A/Al,B/Bl);
res=res*q_pow(PdmuTd[r]*invPdmuTd[l-1]%mod,1ll*Al*Bl%mod1)%mod;
}
return res;
}
ll TYPE0_calc(){
ll res1=q_pow(fac[A],1ll*B*C%mod1);
ll res2=q_pow(fac[B],1ll*A*C%mod1);
ll res3=q_pow(TYPE0_solve(A,B),C);
ll res4=q_pow(TYPE0_solve(A,C),B);
ll res5=res1*res2%mod;
ll res6=res3*res4%mod;
return res5*q_pow(res6,mod-2)%mod;
}
ll TYPE1_solve(int A,int B){
int M=min(A,B);
ll res=1;
for(int l=1,r;l<=M;l=r+1){
int Al=A/l,Bl=B/l;
r=min(A/Al,B/Bl);
res=res*q_pow(PdmuTdTT[r]*invPdmuTdTT[l-1]%mod,S2(Al)*S2(Bl)%mod1)%mod;
}
return res;
}
ll TYPE1_calc(){
ll res1=q_pow(ii[A],S2(B)*S2(C)%mod1);
ll res2=q_pow(ii[B],S2(A)*S2(C)%mod1);
ll res3=q_pow(TYPE1_solve(A,B),S2(C));
ll res4=q_pow(TYPE1_solve(A,C),S2(B));
ll res5=res1*res2%mod;
ll res6=res3*res4%mod;
return res5*q_pow(res6,mod-2)%mod;
}
ll TYPE2_solve1(int A,int B,int C){
int M=min({A,B,C});
ll res=1;
for(int l=1,r;l<=M;l=r+1){
int Al=A/l,Bl=B/l,Cl=C/l;
r=min({A/Al,B/Bl,C/Cl});
res=res*q_pow(fac[Al],(1ll*Bl*Cl%(mod-1))*(Sphi[r]-Sphi[l-1])%mod1)%mod;
}
return res;
}
ll TYPE2_solve2(int A,int B,int C){
int M=min({A,B,C});
ll res=1;
for(int l=1,r;l<=M;l=r+1){
int Al=A/l,Bl=B/l,Cl=C/l;
r=min({A/Al,B/Bl,C/Cl});
res=res*q_pow(TYPE0_solve(Al,Bl),Cl*(Sphi[r]-Sphi[l-1])%mod1)%mod;
}
return res;
}
ll TYPE2_calc(){
ll res1=TYPE2_solve1(A,B,C);
ll res2=TYPE2_solve1(B,A,C);
ll res3=TYPE2_solve2(A,B,C);
ll res4=TYPE2_solve2(A,C,B);
ll res5=res1*res2%mod;
ll res6=res3*res4%mod;
return res5*q_pow(res6,mod-2)%mod;
}
signed main(){
scanf("%d%d",&T,&mod);mod1=mod-1;
init();
while(T--){
scanf("%d%d%d",&A,&B,&C);
ll ans0=TYPE0_calc();
ll ans1=TYPE1_calc();
ll ans2=TYPE2_calc();
printf("%lld %lld %lld\n",ans0,ans1,ans2);
}
return 0;
}