题面
给定三个数 A,B,C,求 p 分别为 1,ijk,gcd(i,j,k) 时,下面式子的值:
i=1∏Aj=1∏Bk=1∏C(gcd(i,j)lcm(i,j))p
多测,对大质数取模。T=70,A,B,C≤105。
题解
显然,lcm(a,b)=gcd(a,b)ab,于是题目转化为:
i=1∏Aj=1∏Bk=1∏C(gcd(i,j)gcd(i,k)ij)p
于是可以拆分为两个子问题做:
F(A,B,C)=i=1∏Aj=1∏Bk=1∏Cip
这个当分子。
G(A,B,C)=i=1∏Aj=1∏Bk=1∏Cgcd(i,j)p
这个当分母。于是:
ans=G(A,B,C)G(A,C,B)F(A,B,C)F(B,A,C)
于是就可以分别讨论了。下面按照 p 的取值分三种情况讨论:
情况一
p=1 的情况:
分子
这个太显然了。
F(A,B,C)=i=1∏Aj=1∏Bk=1∏Ci=(A!)BC
预处理阶乘后,单次询问复杂度 O(logn)。
分母
G(A,B,C)=(i=1∏Aj=1∏Bgcd(i,j))C
莫比乌斯反演:
⎝⎜⎛d=1∏min(A,B)d∑i=1⌊dA⌋∑j=1⌊dB⌋[gcd(i,j)=1]⎠⎟⎞C
上面那个指数我们拿出来考虑一下,还是反演:
i=1∑⌊dA⌋j=1∑⌊dB⌋p∣gcd(i,j)∑μ(p)
这玩意太水了,不难得到:
p=1∑min(⌊dA⌋,⌊dB⌋)μ(p)⌊dpA⌋⌊dpB⌋
因此原式为:
⎝⎜⎛d=1∏min(A,B)d∑p=1min(⌊dA⌋,⌊dB⌋)μ(p)⌊dpA⌋⌊dpB⌋⎠⎟⎞C
太丑了,把指数的求和号拆出来,换个元:
⎣⎢⎢⎡p=1∏min(A,B)⎝⎜⎛d∣p∏dμ(dp)⎠⎟⎞⌊pA⌋⌊pB⌋⎦⎥⎥⎤C
于是设:
f(n)=d∣n∏dμ(dn)
那么原式可以变为:
⎝⎜⎛p=1∏min(A,B)f(p)⌊pA⌋⌊pB⌋⎠⎟⎞C
预处理 f 可以用埃式筛,再预处理 f 的前缀积,询问时整除分块。单次询问复杂度 O(nlogn)。
情况二
p=i×j×k 的情况:
分子
F(A,B,C)=i=1∏Aii×2B(B+1)×2C(C+1)
预处理 ∏ii 即可,单次询问 O(logn)。
分母
提出指数,然后反演得到:
G(A,B,C)=⎝⎜⎛d=1∏min(A,B)d∑i=1⌊dA⌋∑j=1⌊dB⌋id×jd[gcd(i,j)=1]⎠⎟⎞2C(C+1)
然后把指数拉出来莫比乌斯反演:
d2i=1∑⌊dA⌋j=1∑⌊dB⌋ijp∣gcd(i,j)∑μ(p)
套路性换一下顺序:
=d2p=1∑min(⌊dA⌋,⌊dB⌋)p2μ(p)i=1∑⌊dpA⌋ij=1∑⌊dpB⌋j
然后放回去:
⎝⎜⎛d=1∏min(A,B)dd2∑p=1min(⌊dA⌋,⌊dB⌋)p2μ(p)2⌊dpA⌋(⌊dpA⌋+1)2⌊dpB⌋(⌊dpB⌋+1)⎠⎟⎞2C(C+1)
把前面这依托 ∑ 里的东西修一下:
⎣⎢⎢⎢⎢⎡p=1∏min(A,B)⎝⎜⎛d∣p∏dp2μ(dp)⎠⎟⎞2⌊pA⌋(⌊pA⌋+1)×2⌊pB⌋(⌊pB⌋+1)⎦⎥⎥⎥⎥⎤2C(C+1)
于是得到了一个很复杂的式子,设:
f(n)=d∣n∏dn2μ(dn)
那么原式可以变为:
⎣⎢⎡p=1∏min(A,B)f(p)2⌊pA⌋(⌊pA⌋+1)×2⌊pB⌋(⌊pB⌋+1)⎦⎥⎤2C(C+1)
预处理 f 仍然可以埃式筛,然后预处理它的前缀积,这个式子就可以用整除分块求。单次询问复杂度 O(nlogn)。
情况三
正片开始。
p=gcd(i,j,k) 的情况:
分子
F(A,B,C)=d=1∏min(A,B,C)i=1∏Ai∑j=1B∑k=1C[gcd(i,j,k)=d]
感到无从下手?把 i 直接变成 di:
d=1∏min(A,B,C)i=1∏⌊dA⌋(id)d∑j=1⌊dB⌋∑k=1⌊dC⌋[gcd(i,j,k)=1]
还是先考虑指数:
dj=1∑⌊dB⌋k=1∑⌊dC⌋[gcd(i,j,k)=1]
三个数的 gcd 暴力莫反就有点恶心了:
dj=1∑⌊dB⌋k=1∑⌊dC⌋t∣gcd(i,j,k)∑μ(t)
交换求和号的时候,注意 t 需要同时满足能整除 i,j,k:
t=1∑min(⌊dA⌋,⌊dB⌋,⌊dC⌋)dμ(t)[t∣i]j=1∑⌊dB⌋[t∣j]k=1∑⌊dC⌋[t∣k]
没什么思路?把枚举 t 的求和号移到指数下面变成连乘号:
d=1∏min(A,B,C)t=1∏min(⌊dA⌋,⌊dB⌋,⌊dC⌋)i=1∏⌊tdA⌋(itd)dμ(t)⌊tdB⌋⌊tdC⌋
抽个 p 出来换元:
p=1∏min(A,B,C)d∣p∏i=1∏⌊pA⌋(ip)dμ(dp)⌊pB⌋⌊pC⌋
再把第三个 ∏ 搞一下呗:
p=1∏min(A,B,C)⎣⎢⎢⎢⎡d∣p∏⎝⎜⎜⎛p⌊pA⌋i=1∏⌊pA⌋i⎠⎟⎟⎞dμ(dp)⎦⎥⎥⎥⎤⌊pB⌋⌊pC⌋
然后你发现这个指数还可以换一换:
p=1∏min(A,B,C)⎣⎢⎢⎢⎡⎝⎜⎜⎛p⌊pA⌋i=1∏⌊pA⌋i⎠⎟⎟⎞∑d∣pdμ(dp)⎦⎥⎥⎥⎤⌊pB⌋⌊pC⌋
仔细观察现在的指数,是狄利克雷卷积 id∗μ=φ:
p=1∏min(A,B,C)⎣⎢⎢⎢⎡⎝⎜⎜⎛p⌊pA⌋i=1∏⌊pA⌋i⎠⎟⎟⎞φ(p)⎦⎥⎥⎥⎤⌊pB⌋⌊pC⌋
后面的转化就相对常规了:
p=1∏min(A,B,C)⎣⎢⎢⎢⎡p⌊pA⌋φ(p)⎝⎜⎜⎛i=1∏⌊pA⌋i⎠⎟⎟⎞φ(p)⎦⎥⎥⎥⎤⌊pB⌋⌊pC⌋
显然需要预处理阶乘,然后设:
f(n)=nφ(n)
线性筛欧拉函数后可以 nlogn 预处理出来。那么原式可以写为:
p=1∏min(A,B,C)f(p)⌊pA⌋⌊pB⌋⌊pC⌋f(⌊pA⌋!)⌊pB⌋⌊pC⌋
整除分块即可,单次询问 O(nlogn)。
分母
G(A,B,C)=d=1∏min(A,B,C)i=1∏Aj=1∏Bk=1∏Cdgcd(d,k)[gcd(i,j)=d]
套路性再反演一下:
d=1∏min(A,B,C)(d∑i=1A∑j=1B[gcd(i,j)=d])∑k=1Cgcd(d,k)
先考虑最外面的指数吧:
k=1∑Cgcd(d,k)
用欧拉反演 id=φ∗1:
=k=1∑Ct∣gcd(d,k)∑φ(t)=t∣d∑φ(t)⌊tC⌋
然后我们考虑里面那个指数:
i=1∑Aj=1∑B[gcd(i,j)=d]
我们发现,这和情况一的分母部分形式是一样的,这里不赘述:
i=1∑Aj=1∑B[gcd(i,j)=d]=g=1∑min(A,B)μ(g)⌊gdA⌋⌊gdB⌋
于是就可以看看原式变成了什么:
d=1∏min(A,B,C)d(∑g=1min(A,B)μ(g)⌊gdA⌋⌊gdB⌋)×(∑t∣dφ(t)⌊tC⌋)
我们发现,如果预处理 f(d)=∑g=1min(A,B)μ(g)⌊gdA⌋⌊gdB⌋,这个式子可以单次询问 O(nlogn) 完成。如果常数够小的话这个题就做出来了。
当然并不是所有人常数都和 vv 一样小,所以这并不好。
更优的做法
重新考虑这个情况:
i=1∏Aj=1∏Bk=1∏C(gcd(i,k)lcm(i,j))gcd(i,j,k)
我们对其求 ln,把乘法转加法,指数转系数:
i=1∑Aj=1∑Bk=1∑Cgcd(i,j,k)ln(gcd(i,k)lcm(i,j))
于是就可以常规反演了,套路和前面一样就不多赘述:
d=1∑min(A,B,C)φ(d)i=1∑⌊dA⌋j=1∑⌊dB⌋k=1∑⌊dC⌋ln(gcd(i,k)lcm(i,j))
然后我们把它 exp 回来:
d=1∏min(A,B,C)⎝⎜⎜⎛i=1∏⌊dA⌋j=1∏⌊dB⌋k=1∏⌊dC⌋gcd(i,k)lcm(i,j)⎠⎟⎟⎞φ(d)
括号里面的东西和情况一是一样的。预处理欧拉函数和前缀和,单次询问 O(nlogn)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| #include<bits/stdc++.h> #define int long long using namespace std; const int max_n=200005,N=200000;int mod; inline int read(){ int x=0;bool w=0;char c=getchar(); while(c<'0' || c>'9') w|=c=='-',c=getchar(); while(c>='0' && c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return w?-x:x; } inline void write(int x){ if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10^48); } inline int mi(int a,int p=mod-2){ int res=1; a=(a%mod+mod)%mod,p%=mod-1; while(p){ if(p&1) res*=a,res%=mod; a*=a,a%=mod,p>>=1; } return res; }
bool isp[max_n]; int pr[max_n],cntp,mu[max_n],phi[max_n];
inline void Init(int n){ memset(isp,1,sizeof(isp)),isp[1]=0; mu[1]=phi[1]=1; for(register int i=2;i<=n;++i){ if(isp[i]){ pr[++cntp]=i; mu[i]=-1, phi[i]=i-1; } for(register int j=1;j<=cntp && i*pr[j]<=n;++j){ isp[i*pr[j]]=0; if(i%pr[j]==0){ mu[i*pr[j]]=0, phi[i*pr[j]]=phi[i]*pr[j]; break; } mu[i*pr[j]]=-mu[i], phi[i*pr[j]]=phi[i]*phi[pr[j]]; } } }
int A,B,C,fac[max_n],iv[max_n];
namespace TP1{ int f[max_n],inv[max_n]; inline void init(int n){ f[0]=inv[0]=1; for(register int i=0;i<=n;++i) f[i]=1; for(register int i=1;i<=n;++i) for(register int j=i,k=1;j<=n;j+=i,++k) if(mu[k]!=0){ if(mu[k]>0) f[j]*=i; else f[j]*=iv[i]; f[j]%=mod; } for(register int i=1;i<=n;++i){ f[i]=f[i-1]*f[i]%mod, inv[i]=mi(f[i]); } } inline int F(int A,int B,int C){ return mi(fac[A],B*C); } inline int G(int A,int B,int C){ int res=1,up=min(A,B); for(register int l=1,r;l<=up;l=r+1){ r=min(A/(A/l),B/(B/l)); res=res*mi(f[r]*inv[l-1],(A/l)*(B/l))%mod; } return mi(res,C); } inline int sol(int A,int B,int C){ int fz=F(A,B,C)*F(B,A,C)%mod,fm=G(A,B,C)*G(A,C,B)%mod; return fz*mi(fm)%mod; } }
namespace TP2{ int f[max_n],g[max_n],inv[max_n]; inline void init(int n){ f[0]=g[0]=inv[0]=1; for(register int i=1;i<=n;++i){ f[i]=f[i-1]*mi(i,i)%mod, g[i]=g[i-1]*mi(TP1::f[i]*TP1::inv[i-1],i*i)%mod, inv[i]=mi(g[i]); } } inline int Sum(int x){ return x*(x+1)/2%(mod-1); } inline int F(int A,int B,int C){ return mi(f[A],Sum(B)*Sum(C)); } inline int G(int A,int B,int C){ int res=1,up=min(A,B); for(register int l=1,r;l<=up;l=r+1){ r=min(A/(A/l),B/(B/l)); res=res*mi(g[r]*inv[l-1],Sum(A/l)*Sum(B/l))%mod; } return mi(res,Sum(C)); } inline int sol(int A,int B,int C){ int fz=F(A,B,C)*F(B,A,C)%mod,fm=G(A,B,C)*G(A,C,B)%mod; return fz*mi(fm)%mod; } }
namespace TP3{ int f[max_n]; inline void init(int n){ f[1]=1; for(register int i=2;i<=n;++i) f[i]=(f[i-1]+phi[i])%(mod-1); } inline int sol(int A,int B,int C){ int res=1,up=min(A,min(B,C)); for(register int l=1,r;l<=up;l=r+1){ r=min(A/(A/l),min(B/(B/l),C/(C/l))); res=res*mi(TP1::sol(A/l,B/l,C/l),f[r]-f[l-1]+mod-1)%mod; } return res; } }
signed main(){
int T=read();mod=read(); fac[0]=1; for(register int i=1;i<=N;++i) fac[i]=fac[i-1]*i%mod; for(register int i=0;i<=N;++i) iv[i]=mi(i); Init(N), TP1::init(N), TP2::init(N), TP3::init(N); while(T--){ int A=read(),B=read(),C=read(); write(TP1::sol(A,B,C)),putchar(' '); write(TP2::sol(A,B,C)),putchar(' '); write(TP3::sol(A,B,C)),putchar('\n'); } return 0; }
|
附记
他(CYJian)还给你们讲了幽灵乐团??这个人有病吧。
—— CZZ
这完全是拖时间才给你们讲这个吧?
—— HJS