题解 P7890 「MCOI-06」Lost Desire
本题解旨在提供一种简洁的推导方法,减少各位的脑细胞的损耗。
在此题解中,我们约定:
即
那么我们就有 定理
同样地,在
注:以下推导省略向下取整符号
接下来开始推式子,假设
设
这样分子就算推完了,接下来是分母:
记
把分子分母结合起来,就可以得到:
为了能够整除分块,我们设:
那么对于整除分块中的区间
那么我们只需计算出所有需要的
如果再加上 Index Calculus 或其他求离散对数的算法,那就可以通过此题了。
以下给出一个只能过前四个 Subtask 的代码,仅供参考 or 对拍:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
int Read(){
int res = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') res = res * 10 + (c ^ 48), c = getchar();
return res;
}
void Write(int x){ if(x > 9) Write(x / 10); putchar(48 ^ (x % 10));}
const int Mx = 1e6 + 1, Nx = 13970040;
int Mod;
int FastPow(ll a, int b){
int res = 1;
while(b){
if(b & 1) res = res * a % Mod;
b >>= 1, a = a * a % Mod;
}
return res;
}
bool Vis[Mx];
int Prime[78500], tot, Miu[Mx];
int Frac[Mx], Infs[Mx];
int St[Mx];
int MF[Nx], MG[Nx];
void TestifyInit(){
Miu[1] = Frac[0] = Frac[1] = 1;
for(int i = 2; i < Mx; ++i){
if(!Vis[i]) Prime[++tot] = i, Miu[i] = -1;
for(int j = 1; j <= tot && Prime[j] * i < Mx; ++j){
Vis[i * Prime[j]] = 1;
if(i % Prime[j] == 0) break;
Miu[i * Prime[j]] = -Miu[i];
}
Frac[i] = 1ll * Frac[i - 1] * i % Mod;
}
St[1] = -1, Infs[Mx - 1] = FastPow(Frac[Mx - 1], Mod - 2);
for(int i = 1; i < Mx - 1; ++i) St[i + 1] = St[i] + (Mx - 1) / i;
for(int i = Mx - 1; i; --i) Infs[i - 1] = 1ll * Infs[i] * i % Mod;
for(int d = 1; d < Mx; ++d){
int lim = St[d] + (Mx - 1) / d;
if(Miu[d] & 2){
MF[St[d] + 1] = Infs[d], MG[St[d] + 1] = Infs[d - 1];
for(int x = St[d] + 2, t = d; x <= lim; ++x){
MF[x] = 1ll * Infs[t += d] * MF[x - 1] % Mod;
MG[x] = 1ll * Infs[t - 1] * MG[x - 1] % Mod;
}
for(int x = St[d] + 2; x <= lim; ++x) MG[x] = 1ll * MG[x] * MG[x - 1] % Mod;
}
else if(Miu[d]){
MF[St[d] + 1] = Frac[d], MG[St[d] + 1] = Frac[d - 1];
for(int x = St[d] + 2, t = d; x <= lim; ++x){
MF[x] = 1ll * Frac[t += d] * MF[x - 1] % Mod;
MG[x] = 1ll * Frac[t - 1] * MG[x - 1] % Mod;
}
for(int x = St[d] + 2; x <= lim; ++x) MG[x] = 1ll * MG[x] * MG[x - 1] % Mod;
}
else for(int x = St[d] + 1; x <= lim; ++x) MF[x] = MG[x] = 1;
}
for(int d = 2; d < Mx; ++d){
int lim = St[d] + (Mx - 1) / d;
for(int x = St[d] + 1, y = St[d - 1] + 1; x <= lim; ++x, ++y)
MF[x] = 1ll * MF[x] * MF[y] % Mod, MG[x] = 1ll * MG[x] * MG[y] % Mod;
}
}
int main(){
int T = Read(); Mod = Read();
TestifyInit();
while(T--){
int n = Read(), m = Read(), k = Read();
if(n > m) swap(n, m);
int A = MG[n + m - 1];
int B = 1ll * MG[n - 1] * MG[m - 1] % Mod * FastPow(MF[n - 1], m) % Mod * FastPow(MF[m - 1], n) % Mod; // Ans = A / B
for(int l = 2, r; l <= n; l = r + 1){
int N = n / l, M = m / l;
r = min(n / N, m / M);
A = 1ll * A * MG[St[r] + N + M] % Mod
* MG[St[l - 1] + N] % Mod
* MG[St[l - 1] + M] % Mod
* FastPow(MF[St[l - 1] + N], M) % Mod
* FastPow(MF[St[l - 1] + M], N) % Mod;
B = 1ll * B * MG[St[l - 1] + N + M] % Mod
* MG[St[r] + N] % Mod
* MG[St[r] + M] % Mod
* FastPow(MF[St[r] + N], M) % Mod
* FastPow(MF[St[r] + M], N) % Mod;
}
printf("%d\n", FastPow(1ll * A * FastPow(B, Mod - 2) % Mod, k));
}
return 0;
}