题解:P5518 [MtOI2019] 幽灵乐团 / 莫比乌斯反演基础练习题
绝对是基础练习题哈!推式子不是世界上最快乐的事情嘛。
题目大意:在 \(p\) 分别定义为 \(1\)、\(ijk\)、\(\gcd(i,j,k)\) 下求 \(\displaystyle \prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\left ( \frac{\text{lcm}(i, j)}{\gcd(i, k)}\right)^p\)
莫反
首先可以将题意转化成 \(\displaystyle \prod_{i=1}^{A}\prod_{j=1}^{B}\prod_{k=1}^{C}\left ( \frac{ij}{\gcd(i, j)\gcd(i, k)}\right)^p\)。
观察式子,发现可以拆成 \(\displaystyle \prod _ {i = 1} ^ A \prod _ {j = 1} ^ {B} \prod _ {k = 1} ^ {C}i^p\) 与 \(\displaystyle \prod _ {i = 1} ^ A \prod _ {j = 1} ^ {B} \prod _ {k = 1} ^ {C}\gcd(i, j)^p\) 两个部分。
若 \(p=1\)。
预处理阶乘、手搓快速幂即可。
预处理 \(\displaystyle\left(\prod_{d \mid e} d^{\mu\left( \frac{e}{d} \right)} \right)\),然后数论分块。
若 \(p = ijk\)。
可以直接预处理括号内的式子。
预处理 \(\displaystyle\left(\prod_{d \mid e} d^{\mu\left( \frac{e}{d} \right)} \right) ^ {e^2}\)。
若 \(p = \gcd(i, j, k)\)。
畏惧了,去学习了人类智慧前来迎战。
然后就是线性筛、数论分块之类的东西了。
#include <bits/stdc++.h>
//#define fastio
#define int long long
#define bw(x) (1 << x)
#define eb emplace_back
#define pii pair<int, int>
#define inf 0x3f3f3f3f3f3f3f3f
#define F(x, v) for (auto x : (v))
#define ALL(x) (x).begin(), (x).end()
#define L(i, a, b) for (register int i = (a); i <= (b); ++i)
#define R(i, a, b) for (register int i = (a); i >= (b); --i)
#define FRE(i, o) freopen(i, "r", stdin), freopen(o, "w", stdout)
using namespace std; bool bgmem;
#ifdef fastio
struct IO {
#define ion bw(20)
char i[ion], o[ion], *icl = i, *icr = i, *oc = o;
__inline char gc() { return (icl == icr && (icr = (icl = i) + fread(i, 1, ion, stdin), icl == icr)) ? EOF : *icl++; }
__inline void pc(char c) { if (oc - o == ion) fwrite(o, 1, ion, stdout), oc = o; *oc++ = c; }
__inline void rd(auto &x) { char c; int f = 1; x = 0; while (c = gc(), c < '0' || c > '9') if (c == '-') f = -1; while ('0' <= c && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = gc(); x *= f; }
__inline void pr(auto x) { int a[64], p = 0; if (x < 0) x = -x, pc('-'); do a[p++] = x % 10; while (x /= 10); while (p--) pc(a[p] + '0'); }
IO& operator>>(char &c) { return c = gc(), *this; }
IO& operator<<(char c) { return pc(c), *this; }
IO& operator<<(const char *c) { while (*c) pc(*c++); return *this; }
IO& operator>>(auto &x) { return rd(x), *this; }
IO& operator<<(auto x) { return pr(x), *this; }
} io;
#define cin io
#define cout io
#endif
const int N = 1e5 + 10;
__inline int cmax(int& x, int c) { return x = max(x, c); }
__inline int cmin(int& x, int c) { return x = min(x, c); }
int tes = 1, cas;
namespace zrh {
bool ip[N]; int mu[N], P, phi[N], p[N], sum1[N], sum2[N], fac[N], cnt, in1[N], in2[N], ipi[N];
int fpw(int x, int y) {
int ans = 1;
for (; y; y >>= 1, x = x * x % P) if (y & 1) ans = ans * x % P;
return ans;
}
int S(int x) { return (x * (x + 1) / 2) % (P - 1); }
int calc1(int x, int y) {
int lim = min(x, y), ans = 1;
L(l, 1, lim) {
int r = min(x / (x / l), y / (y / l));
ans = ans * fpw(sum1[r] * in1[l - 1] % P, (x / l) * (y / l) % (P - 1)) % P;
l = r;
}
return ans;
} int calc2(int x, int y) {
int lim = min(x, y), ans = 1;
L(l, 1, lim) {
int r = min(x / (x / l), y / (y / l));
ans = ans * fpw(sum2[r] * in2[l - 1] % P, S(x / l) * S(y / l) % (P - 1)) % P;
l = r;
}
return ans;
} int sol1(int a, int b, int c) {
int ansz = fpw(fac[a], b * c % (P - 1)) * fpw(fac[b], a * c % (P - 1)) % P;
int ansm = fpw(calc1(a, b), c) * fpw(calc1(a, c), b) % P;
return ansz * fpw(ansm, P - 2) % P;
} int sol2(int a, int b, int c) {
int ansz = fpw(fpw(ipi[a], S(b)) * fpw(ipi[b], S(a)) % P, S(c));
int ansm = fpw(calc2(a, b), S(c)) * fpw(calc2(a, c), S(b)) % P;
return ansz * fpw(ansm, P - 2) % P;
} int sol3(int a, int b, int c) {
int lim = min(a, min(b, c)), ans = 1;
L(l, 1, lim) {
int r = min(a / (a / l), min(b / (b / l), c / (c / l)));
ans = ans * fpw(sol1(a / l, b / l, c / l), (phi[r] - phi[l - 1]) % (P - 1)) % P;
l = r;
}
return ans;
}
void init() {
mu[1] = phi[1] = 1;
L(i, 2, N - 10) {
if (!ip[i]) p[++cnt] = i, mu[i] = -1, phi[i] = i - 1;
for (int j = 1; j <= cnt && i * p[j] <= N - 10; ++j) {
ip[i * p[j]] = 1;
if (i % p[j] == 0) { mu[i * p[j]] = 0, phi[i * p[j]] = phi[i] * p[j]; break; }
mu[i * p[j]] = -mu[i], phi[i * p[j]] = phi[i] * phi[p[j]];
}
}
sum1[0] = in1[0] = in2[0] = 1; L(i, 1, N - 10) sum1[i] = 1, phi[i] += phi[i - 1];
L(i, 1, N - 10) for (int j = i; j <= N - 10; j += i) sum1[j] = sum1[j] * fpw(i, (mu[j / i] + P - 1) % (P - 1)) % P;
L(i, 0, N - 10) sum2[i] = fpw(sum1[i], i * i % (P - 1));
L(i, 1, N - 10) sum1[i] = sum1[i - 1] * sum1[i] % P, in1[i] = fpw(sum1[i], P - 2);
L(i, 1, N - 10) sum2[i] = sum2[i - 1] * sum2[i] % P, in2[i] = fpw(sum2[i], P - 2);
fac[0] = 1; L(i, 1, N - 10) fac[i] = fac[i - 1] * i % P;
ipi[0] = 1; L(i, 1, N - 10) ipi[i] = ipi[i - 1] * fpw(i, i) % P;
}
void clear() {}
void solve() {
int A, B, C; cin >> A >> B >> C;
cout << sol1(A, B, C) << " " << sol2(A, B, C) << " " << sol3(A, B, C) << "\n";
}
} // namespace zrh
bool edmem; signed main() {
// FRE("", "");
#ifndef fastio
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
#endif
cin >> tes >> zrh::P;
zrh::init(); while (++cas <= tes) zrh::clear(), zrh::solve();
#ifdef fastio
fwrite(io.o, 1, io.oc - io.o, stdout);
#endif
cerr << "time : " << (double)clock() / CLOCKS_PER_SEC * 1000 << "ms\n";
cerr << "memory: " << fabs(&edmem - &bgmem) / 1024 / 1024 << "mb\n";
return 0;
}
// I will never love zrh again. =(

浙公网安备 33010602011771号