题目
分析
枚举
p
p
p 到
⌊
N
j
⌋
\left\lfloor\frac{N}{j}\right\rfloor
⌊jN⌋ 实际上就是在枚举
j
p
jp
jp,于是原式变成
∑
i
=
1
N
∑
j
=
1
N
∑
p
=
1
N
∑
q
=
1
N
[
gcd
(
i
,
j
)
=
1
]
[
gcd
(
p
,
q
)
=
j
]
=
∑
i
=
1
N
∑
j
=
1
N
∑
p
=
1
N
∑
q
=
1
N
[
gcd
(
i
,
p
,
q
)
=
1
]
=
∑
d
=
1
N
⌊
N
d
⌋
3
μ
(
d
)
\begin{aligned}&\sum_{i = 1}^N\sum_{j = 1}^N\sum_{p = 1}^{N}\sum_{q = 1}^{N}[\gcd(i, j) = 1][\gcd(p, q) = j] \\= &\sum_{i = 1}^N\sum_{j = 1}^N\sum_{p = 1}^{N}\sum_{q = 1}^{N}[\gcd(i, p, q) = 1] \\=&\sum_{d = 1}^{N}\left\lfloor\frac{N}{d}\right\rfloor^3\mu(d)\end{aligned}
==i=1∑Nj=1∑Np=1∑Nq=1∑N[gcd(i,j)=1][gcd(p,q)=j]i=1∑Nj=1∑Np=1∑Nq=1∑N[gcd(i,p,q)=1]d=1∑N⌊dN⌋3μ(d) 整数分块 + 杜教筛即可。
代码
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 1000000;
const int MOD = 998244353;
int Mu[MAXN + 5];
bool Vis[MAXN + 5];
std::vector<int> Primes;
std::unordered_map<int, int> Sum;
void Init(int n) {
Mu[1] = 1;
for (int i = 2; i <= n; i++) {
if (!Vis[i])
Mu[i] = -1, Primes.push_back(i);
for (int j = 0; j < (int)Primes.size() && i * Primes[j] <= n; j++) {
Vis[i * Primes[j]] = true;
if (i % Primes[j] == 0) {
Mu[i * Primes[j]] = 0;
break;
}
Mu[i * Primes[j]] = -Mu[i];
}
Mu[i] = ((Mu[i - 1] + Mu[i]) % MOD + MOD) % MOD;
}
}
int GetSum(int n) {
if (n <= MAXN) return Mu[n];
if (Sum.count(n)) return Sum[n];
int res = 1;
for (int lft = 2, rgt = 1; lft <= n; lft = rgt + 1) {
rgt = n / (n / lft);
res = (res - (LL)(rgt - lft + 1) * GetSum(n / lft) % MOD) % MOD;
}
return Sum[n] = (res + MOD) % MOD;
}
int main() {
Init(MAXN);
int N, Ans = 0; scanf("%d", &N);
for (int lft = 1, rgt = 1; lft <= N; lft = rgt + 1) {
rgt = N / (N / lft);
Ans = (Ans + ((LL)(GetSum(rgt) - GetSum(lft - 1)) * (N / lft) % MOD * (N / lft) % MOD * (N / lft) % MOD)) % MOD;
}
printf("%d", (Ans + MOD) % MOD);
return 0;
}