题目链接:https://www.luogu.com.cn/problem/P5518
T次给出A,B,C求以下三个式子
A∏i=1B∏j=1C∏k=1lcm(i,j)gcd(i,k)
A∏i=1B∏j=1C∏k=1(lcm(i,j)gcd(i,k))i×j×k
A∏i=1B∏j=1C∏k=1(lcm(i,j)gcd(i,k))gcd(i,j,k)
1≤T≤70,1≤A,B,C≤105
开始写了个O(Tnlogn)结果发现不能过,然后就多浪费了三个多小时

只需要用到两个反演的式子
F(i)=∑i|df(d)⇒f(i)=∑i|dμ(di)F(d)
gcd(S)=∑∀x∈S,d|xφ(d)
然后因为推导过程出来冗长以外没有太多难的部分,所以推荐自己手推到不会的再翻题解。
然后就开始吧,因为lcm(i,j)=ijgcd(i,j)所以问题可以化为两个部分,求
(A∏i=1B∏j=1C∏k=1ij)f(type),(A∏i=1B∏j=1C∏k=11gcd(i,j))f(type)
首先是第一个式子f(type)=1。
第一部分就是
A∏i=1iB×C×B∏j=1jA×C
这个十分简单,我们预处理阶乘就可以做到O(logP)
然后第二部分考虑枚举约数
∏d=11dC×∑Ai=1∑Bj=1[gcd(i,j)=d]
然后莫反
∏d=11dC∑k=1μ(k)⌊Akd⌋⌊Bkd⌋
显然的我们可以d,k都可以整除分块,预处理一下逆元的前缀乘积就可以快速计算区间逆元乘积了。
第一个式子时间复杂度O(n34)
然后第二个式子类似的,记S(n)=n×(n+1)2那么有
A∏i=1iiS(B)S(C)×B∏j=1jjS(A)(C)
维护一个ii的前缀积即可。
第二部分
∏d=11dS(C)×∑Ai=1∑Bj=1ij[gcd(i,j)=d]⇒∏d=11dS(C)∑k=1μ(k)S(⌊Akd⌋)S(⌊Bkd⌋)
需要提前处理μ(i)×i2的前缀和,i2,1i2的前缀积就好了
第二个式子时间复杂度O(n34)
主要的难点在第三个式子
首先第一部分先只考虑i
A∏i=1B∏j=1C∏k=1igcd(i,j)
考虑欧拉反演,枚举约数
∏d=1⎛⎜⎝⌊Ad⌋∏ii×d⎞⎟⎠φ(d)⌊Bd⌋⌊Cd⌋
设fi=∏ij=1i那么有
∏d=1(f⌊Ad⌋d⌊Ad⌋)φ(d)⌊Bd⌋⌊Cd⌋
拆开来f和d的部分
∏d=1(f⌊Ad⌋)φ(d)⌊Bd⌋⌊Cd⌋×dφ(d)⌊Ad⌋⌊Bd⌋⌊Cd⌋
预处理出f数组,和g数组gi=∏ij=1jφ(j),φ的前缀和就可以整除分块搞了
然后是第二部分
A∏i=1B∏j=1C∏k=11gcd(i,j)gcd(i,j,k)
你可以试一下枚举gcd(i,j),反正我推了好久都没有对出来/kk
所以考虑枚举gcd(i,j,k)的约数然后欧拉反演里面再莫反
∏d=1(∏k=11dk∑z=1μ(z)⌊Adkz⌋⌊Bdkz⌋)φ(d)⌊Cd⌋
然后把1d和1k分开处理
∏d=1(∏k=11k∑z=1μ(z)⌊Adkz⌋⌊Bdkz⌋)φ(d)⌊Cd⌋
×∏d=1(1d)φ(d)⌊Cd⌋∑k=1∑z=1μ(z)⌊Adkz⌋⌊Bdkz⌋
(至于为什么要这么分开,会注意到第一个式子如果我们进行两次整除分块,那么对于每个1dk就会有两个影响它的指数φ(d)和∑z=1μ(z)⌊Adkz⌋⌊Bdkz⌋所以很难处理,此时我们分开来就可以直接用区间的值来做了)
注意到这样要做三次整除分块,十分地慢,但是考虑后面那个式子∑z=1μ(z)⌊Adkz⌋⌊Bdkz⌋对于一个固定的dk是一个确定的值的,并且因为是整除分块,所以不同的值不多我们可以考虑预处理这个东西,整除分块一个dk然后里面再整除分块计算就好了。
还有拆开后处理1d的式子需要预处理1dφ(d)的前缀积。
然后就做完了,第三部分时间复杂度O(n+n34logn)
实际上其实最后的式子两个部分可以约掉一些东西省一些常数,但是这样做也能过但是得开int。
或者你可以用别的方法卡卡常反正我开int了。
因为中途long long改int所以代码巨丑
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
int T,P,Phi,A,B,C,ans,cnt;bool v[N];
int pri[N/10],mu[N],su[N],phi[N],f[N],g[N],h[N];
int inv[N],inc[N],inw[N],fac[N],gac[N],hac[N];
int power(int x,int b){
int ans=1;b=(b%Phi+Phi)%Phi;
while(b){
if(b&1)ans=ans*1ll*x%P;
x=x*1ll*x%P;b>>=1;
}
return ans;
}
int Sum(int n)
{return n*1ll*(n+1)/2%Phi;}
int Tum(int n)
{return n*1ll*(n+1)*1ll*(2ll*1ll*n+1)/6ll%Phi;}
void Prime(){
mu[1]=phi[1]=1;
for(int i=2;i<N;i++){
if(!v[i])pri[++cnt]=i,mu[i]=-1,phi[i]=i-1;
for(int j=1;j<=cnt&&i*1ll*pri[j]<N;j++){
v[i*1ll*pri[j]]=1;
if(i%pri[j]==0){
phi[i*1ll*pri[j]]=phi[i]*1ll*pri[j];
break;
}
mu[i*1ll*pri[j]]=-mu[i];
phi[i*1ll*pri[j]]=phi[i]*1ll*(pri[j]-1);
}
}
inc[1]=fac[0]=gac[0]=inw[0]=inv[0]=hac[0]=1;
for(int i=2;i<N;i++)inc[i]=P-inc[P%i]*1ll*(P/i)%P;
for(int i=1;i<N;i++)fac[i]=fac[i-1]*1ll*i%P;
for(int i=1;i<N;i++)gac[i]=gac[i-1]*1ll*power(i,i)%P;
for(int i=1;i<N;i++)hac[i]=hac[i-1]*1ll*power(i,i*1ll*i%Phi)%P;
for(int i=1;i<N;i++)inw[i]=inw[i-1]*1ll*power(inc[i],i*1ll*i%Phi)%P;
for(int i=1;i<N;i++)inv[i]=inv[i-1]*1ll*inc[i]%P;
for(int i=1;i<N;i++)su[i]=su[i-1]+mu[i];
g[0]=h[0]=1;
for(int i=1;i<N;i++)g[i]=g[i-1]*1ll*power(inc[i],phi[i])%P;
for(int i=1;i<N;i++)h[i]=h[i-1]*1ll*power(i,phi[i])%P;
for(int i=1;i<N;i++)(phi[i]+=phi[i-1])%=Phi;
return;
}
void qart1(int A,int B,int C){
int n=min(A,B);
for(int L=1,R;L<=n;L=R+1){
R=min(A/(A/L),B/(B/L));
int a=A/L,b=B/L,m=min(a,b),w=0;
for(int l=1,r;l<=m;l=r+1){
r=min(a/(a/l),b/(b/l));
(w+=(su[r]-su[l-1])*(a/l)*1ll*(b/l)%Phi)%=Phi;
}
ans=ans*1ll*power(inv[R]*1ll*fac[L-1]%P,w*1ll*C%Phi)%P;
}
return;
}
void part1(){
ans=power(fac[A],B*1ll*C%Phi)*1ll*power(fac[B],A*1ll*C%Phi)%P;
qart1(A,B,C);qart1(A,C,B);
printf("%d ",ans);return;
}
void qart2(int A,int B,int C){
int n=min(A,B);
for(int i=1;i<=n;i++)f[i]=(f[i-1]+mu[i]*1ll*i*1ll*i%Phi)%Phi;
for(int L=1,R;L<=n;L=R+1){
R=min(A/(A/L),B/(B/L));
int a=A/L,b=B/L,m=min(a,b),w=0;
for(int l=1,r;l<=m;l=r+1){
r=min(a/(a/l),b/(b/l));
(w+=Sum(a/l)*1ll*Sum(b/l)%Phi*1ll*(f[r]-f[l-1])%Phi)%=Phi;
}
w=w*1ll*Sum(C)%Phi;
ans=ans*1ll*power(inw[R]*1ll*hac[L-1]%P,w)%P;
}
return;
}
void part2(){
ans=power(gac[A],Sum(B)*1ll*Sum(C)%Phi)*1ll*power(gac[B],Sum(A)*1ll*Sum(C)%Phi)%P;
qart2(A,B,C);qart2(A,C,B);
printf("%d ",ans);return;
}
void qart3(int A,int B,int C){
int n=min(A,B);
for(int L=1,R;L<=n;L=R+1){
R=min(A/(A/L),B/(B/L));
int a=A/L,b=B/L,m=min(a,b),w=0;
for(int l=1,r;l<=m;l=r+1){
r=min(a/(a/l),b/(b/l));
(w+=1ll*(a/l)*(b/l)*(su[r]-su[l-1])%Phi)%=Phi;
}
for(int i=L;i<=R;i++)f[i]=w;
}
n=min(n,C);
for(int L=1,R;L<=n;L=R+1){
R=min(A/(A/L),min(B/(B/L),C/(C/L)));
int a=A/L,b=B/L,c=C/L,m=min(a,b),w=0,s=1;
for(int l=1,r;l<=m;l=r+1){
r=min(a/(a/l),b/(b/l));
(w+=1ll*f[l*1ll*L]*(r-l+1)%Phi)%=Phi;
s=1ll*s*power(1ll*inv[r]*fac[l-1]%P,f[l*1ll*L])%P;
}
ans=ans*1ll*power(1ll*g[R]*power(g[L-1],P-2)%P,1ll*w*(C/L)%Phi)%P;
ans=ans*1ll*power(s,1ll*(phi[R]-phi[L-1])*(C/L)%Phi)%P;
}
return;
}
void part3(){
ans=1;
int n=min(A,min(B,C));
for(int L=1,R;L<=n;L=R+1){
R=min(A/(A/L),min(B/(B/L),C/(C/L)));
int a=A/L,b=B/L,c=C/L;
ans=1ll*ans*power(fac[a],1ll*(phi[R]-phi[L-1])*b*c%Phi)%P;
ans=1ll*ans*power(fac[b],1ll*(phi[R]-phi[L-1])*a*c%Phi)%P;
ans=1ll*ans*power(h[R]*1ll*power(h[L-1],P-2)%P,2ll*a*b*c%Phi)%P;
}
qart3(A,B,C);qart3(A,C,B);
printf("%d ",ans);return;
}
signed main()
{
scanf("%d%d",&T,&P);
Phi=P-1;Prime();
while(T--){
scanf("%d%d%d",&A,&B,&C);
part1();
part2();
part3();
putchar('\n');
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构