【题解】Luogu P5518 题解
Description
令:
给定 ,求:
多测,对给定质数 取模。
,,。
Solution
首先对原式化简一下:
于是原式可以分为两个部分:
显然有:
接下来就开始推柿子吧!
预处理阶乘,每次计算快速幂即可。
然后开始莫反:
把指数提出来推一下:
带回去就有:
最里面括号内的东西可以用类似埃氏筛的方法预处理一下,即对于每个 ,将它的贡献累乘到它的每个倍数上。预处理完成后就可以快乐的整除分块了。
定义:。
然后开始推柿子:
预处理 即可。
把指数拎出来:
带回去:
括号里的东西其实就是第一问预处理的那个东西的 次方,预处理一下即可整除分块。
毒瘤。
这玩意有点复杂,把它拆成两个部分:
可以整除分块了,把 先放着,看 :
指数上的东西:
然后带回去:
这玩意不怎么好预处理。考虑把底数的 拆成 和 :
分别推一下:
括号里的东西预处理过了,两次整除分块可以搞定。
注意到, 和之前的 其实是一样的,而且它们的值不受 顺序的影响,因此可以把它们约掉。
卡常小技巧(不过应该众所周知):把预处理的东西的逆元同时预处理出来可以大幅减小常数
code:
#include <cstdio>
const int N = 1e5,maxn = N + 5;
int T,p,phi,A,B,C,ta,tb,tc;
int pri[maxn],mu[maxn],Inv[maxn],f[maxn],Phi[maxn];
int fac[maxn],fd[maxn],facInv[maxn],fdInv[maxn];
int Fac[maxn],Fd[maxn],FdInv[maxn],ps[maxn];
bool isp[maxn];
inline int read() {
#define gc c = getchar()
int d = 0,f = 0,gc;
for(;c < 48 || c > 57;gc) f |= (c == '-');
for(;c > 47 && c < 58;gc) d = (d << 1) + (d << 3) + (c ^ 48);
#undef gc
return f ? -d : d;
}
inline int Mul(int a,int b,int mod) { return 1LL * a * b % mod; }
inline int Add(int a,int b,int mod) { a += b; return a > mod ? a - mod : a; }
inline int max(int a,int b) { return a > b ? a : b; }
inline int min(int a,int b) { return a < b ? a : b; }
inline int min(int a,int b,int c) { return min(min(a,b),c); }
inline int fpow(int a,int b,int mod) {
int res = 1;
for(;b;a = Mul(a,a,mod),b >>= 1) if(b & 1) res = Mul(res,a,mod);
return res;
}
inline int GetInv(int a) { return a <= N ? Inv[a] : fpow(a,p - 2,p); }
namespace Type0 {
inline int F(int A,int B,int C) { return fpow(fac[A],Mul(B,C,phi),p); }
inline int G(int A,int B,int C) {
int res,ans = 1;
for(int r,l = 1;l <= A && l <= B;l = r + 1) {
ta = A / l,tb = B / l; r = min(A / ta,B / tb);
res = Mul(fd[r],fdInv[l - 1],p);
ans = Mul(ans,fpow(res,Mul(ta,tb,phi),p),p);
}
return fpow(ans,C,p);
}
inline int solve() {
int res = Mul(F(A,B,C),F(B,A,C),p);
int inv = Mul(G(A,B,C),G(A,C,B),p);
return Mul(res,GetInv(inv),p);
}
}
namespace Type1 {
inline int S(int n) { return 1LL * n * (n + 1) / 2 % phi; }
inline int F(int A,int B,int C) { return fpow(Fac[A],Mul(S(B),S(C),phi),p); }
inline int G(int A,int B,int C) {
int res,ans = 1;
for(int r,l = 1;l <= A && l <= B;l = r + 1) {
ta = A / l,tb = B / l;
r = min(A / ta,B / tb);
res = Mul(Fd[r],FdInv[l - 1],p);
ans = Mul(ans,fpow(res,Mul(S(ta),S(tb),phi),p),p);
}
return fpow(ans,S(C),p);
}
inline int solve() {
int res = Mul(F(A,B,C),F(B,A,C),p);
int inv = Mul(G(A,B,C),G(A,C,B),p);
return Mul(res,GetInv(inv),p);
}
}
namespace Type2 {
inline int F(int A,int B,int C) {
int exp,res,ans = 1;
for(int r,l = 1;l <= min(A,B,C);l = r + 1) {
ta = A / l,tb = B / l,tc = C / l;
r = min(A / ta,B / tb,C / tc);
exp = Add(ps[r],phi - ps[l - 1],phi);
res = fpow(fac[ta],Mul(tb,tc,phi),p);
ans = Mul(ans,fpow(res,exp,p),p);
}
return ans;
}
inline int g0(int A,int B) {
int res,ans = 1;
for(int r,l = 1;l <= A && l <= B;l = r + 1) {
ta = A / l,tb = B / l;
r = min(A / ta,B / tb);
res = Mul(fd[r],fdInv[l - 1],p);
ans = Mul(ans,fpow(res,Mul(ta,tb,phi),p),p);
}
return ans;
}
inline int G(int A,int B,int C) {
int res,ans = 1;
for(int r,l = 1;l <= min(A,B,C);l = r + 1) {
ta = A / l,tb = B / l,tc = C / l;
r = min(A / ta,B / tb,C / tc);
res = fpow(g0(ta,tb),tc,p);
ans = Mul(ans,fpow(res,Add(ps[r],phi - ps[l - 1],phi),p),p);
}
return ans;
}
inline int solve() {
int res = Mul(F(A,B,C),F(B,A,C),p);
int inv = Mul(G(A,B,C),G(A,C,B),p);
return Mul(res,GetInv(inv),p);
}
}
inline void Init() {
mu[1] = Phi[1] = f[1] = Inv[0] = Inv[1] = 1;
fac[0] = fac[1] = Fac[0] = facInv[0] = 1;
fd[0] = Fd[0] = fdInv[0] = FdInv[0] = 1;
for(int i = 2;i <= N;i ++) {
f[i] = 1,fac[i] = Mul(i,fac[i - 1],p);
if(!isp[i]) pri[++ pri[0]] = i,mu[i] = -1,Phi[i] = i - 1;
for(int j = 1;j <= pri[0] && i * pri[j] <= N;j ++) {
isp[i * pri[j]] = true;
if(!(i % pri[j])) {
mu[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]];
}
}
facInv[N] = fpow(fac[N],p - 2,p);
for(int i = N - 1;i;i --) {
facInv[i] = Mul(facInv[i + 1],i + 1,p);
Inv[i + 1] = Mul(facInv[i + 1],fac[i],p);
}
for(int i = 1;i <= N;i ++) {
ps[i] = Add(Phi[i],ps[i - 1],phi);
Fac[i] = Mul(Fac[i - 1],fpow(i,i,p),p);
fd[i] = Mul(f[i],fd[i - 1],p);
Fd[i] = Mul(fpow(f[i],Mul(i,i,phi),p),Fd[i - 1],p);
fdInv[i] = GetInv(fd[i]),FdInv[i] = GetInv(Fd[i]);
if(!mu[i]) continue;
for(int j = 1;i * j <= N;j ++)
f[i * j] = Mul(f[i * j],mu[i] == 1 ? j : Inv[j],p);
}
}
int main() {
T = read(),p = read();
phi = p - 1; Init();
for(;T;T --) {
A = read(),B = read(),C = read();
printf("%d %d %d\n",Type0::solve(),Type1::solve(),Type2::solve());
}
return 0;
}
本文作者:Resory
本文链接:https://www.cnblogs.com/resorie/p/soln-lg-p5518.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步