[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;
}
posted @ 2023-12-29 00:11  MoyouSayuki  阅读(12)  评论(0编辑  收藏  举报
:name :name