[P4240] 毒瘤之神的考验 题解
[P4240] 毒瘤之神的考验 题解
知道:
\[\varphi(ij)\varphi(\gcd(i, j)) = \varphi (i)\varphi(j)\gcd(i, j)
\]
可以进行转化,之后可以化简出形如:
\[\sum_{i = 1}^n g(i)f(i, n/i)f(i, m / i)
\]
的式子,其中 \(f,g\) 可以预处理。
对于这个式子,我们可以考虑设 \(S(a, b, c) = g(c)f(c,a)f(b,a)\)。
观察到 \(ac\le n, bc\le m\),考虑根号分治。
对于 \(i\le \sqrt n\),每次爆算,对于 \(i > \sqrt n\),这带来了 \(a\le \sqrt n, b\le \lfloor \dfrac mi \rfloor\),后者差不多也是根号的,可以证明,如果对于 \(a\le \sqrt N, b\le \sqrt N, c\le \sqrt N / b\) 预处理所有的 \(S\),时间复杂度为 \(O(N\ln N)\)。
于是这题就做完了。
// Problem: P4240 毒瘤之神的考验
// Contest: Luogu
// Author: Moyou
// Copyright (c) 2023 Moyou All rights reserved.
// Date: 2023-12-28 00:18:32
#include <algorithm>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 1e5 + 10, mod = 998244353, M = 335;
int primes[N], tot, phi[N], mu[N];
bool st[N];
int qmi(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = 1ll * res * a % mod;
b >>= 1, a = 1ll * a * a % mod;
}
return res;
}
int g[N];
vector<int> f[N], s[M][M];
inline void sieve() {
mu[1] = phi[1] = 1;
for(int i = 2; i <= N - 5; i ++) {
if(!st[i]) primes[++ tot] = i, mu[i] = -1, phi[i] = i - 1;
for(int j = 1; j <= tot && primes[j] * i <= N - 5; j ++) {
st[i * primes[j]] = 1;
if(i % primes[j] == 0) {
phi[i * primes[j]] = phi[i] * primes[j];
break;
}
phi[i * primes[j]] = phi[i] * (primes[j] - 1), mu[i * primes[j]] = -mu[i];
}
}
for(int i = 1; i <= N - 5; i ++) {
int tmp = 1ll * i * qmi(phi[i], mod - 2) % mod;
for(int j = i; j <= N - 5; j += i)
g[j] = (g[j] + tmp * mu[j / i]) % mod;
}
for(int k = 1; k <= N - 5; k ++) {
f[k].resize((N - 5) / k + 1);
for(int i = 1; i <= (N - 5) / k; i ++)
f[k][i] = (f[k][i - 1] + phi[i * k]) % mod;
}
for(int a = 1; a <= M - 5; a ++) {
for(int b = a; b <= M - 5; b ++) {
s[a][b].resize((N - 5) / b + 1);
for(int c = 1; c <= (N - 5) / b; c ++)
s[a][b][c] = (1ll * f[c][a] * f[c][b] % mod * g[c] % mod + s[a][b][c - 1]) % mod;
}
}
}
inline void work() {
int n, m;
cin >> n >> m;
if(n > m) swap(n, m);
int ans = 0;
for(int l = 1, r; l <= n; l = r + 1)
r = min(n / (n / l), m / (m / l)),
ans = (ans + (l == r ? (1ll * f[l][n / l] * f[l][m / l] % mod * g[l] % mod) : (s[n / l][m / l][r] - s[n / l][m / l][l - 1]))) % mod;
cout << (ans + mod) % mod << '\n';
return ;
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
sieve();
int T = 1;
cin >> T;
while (T--) work();
return 0;
}