题目链接
题解:
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
\sum_{i=1}^{n}\sum_{j=1}^{m}[gcd(i,j)=d]
∑i=1n∑j=1m[gcd(i,j)=d]
=
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
g
c
d
(
i
,
j
)
=
1
]
=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1]
=∑i=1⌊dn⌋∑j=1⌊dm⌋[gcd(i,j)=1]
=
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
∑
d
∣
g
c
d
(
i
,
j
)
μ
(
d
)
=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{d\mid gcd(i,j)}\mu(d)
=∑i=1⌊dn⌋∑j=1⌊dm⌋∑d∣gcd(i,j)μ(d)
=
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
∑
d
∣
i
,
d
∣
j
μ
(
d
)
=\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{d\mid i ,d\mid j}\mu(d)
=∑i=1⌊dn⌋∑j=1⌊dm⌋∑d∣i,d∣jμ(d)
∑
d
=
1
m
i
n
{
⌊
n
d
⌋
,
⌊
m
d
⌋
}
μ
(
d
)
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
\sum_{d=1}^{min\{\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor\}}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}
∑d=1min{⌊dn⌋,⌊dm⌋}μ(d)∑i=1⌊dn⌋∑j=1⌊dm⌋
∑
d
=
1
m
i
n
{
⌊
n
d
⌋
,
⌊
m
d
⌋
}
μ
(
d
)
⌊
n
d
⌋
⌊
m
d
⌋
\sum_{d=1}^{min\{\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor\}}\mu(d)\lfloor\frac{n}{d}\rfloor\lfloor\frac{m}{d}\rfloor
∑d=1min{⌊dn⌋,⌊dm⌋}μ(d)⌊dn⌋⌊dm⌋
对于
μ
(
n
)
\mu(n)
μ(n)可以先预处理出其前缀和,然后分块求解。
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define mes(a, val) memset(a, val, sizeof a)
#define ll long long
const int maxn = 5e4 + 100;
int p[maxn], mu[maxn];
bool v[maxn];
int m;
void sieze(int n)
{
m = 0; mes(v, false);
mu[1] = 1;
for(int i = 2; i <= n; i ++){
if(!v[i]){
p[++ m] = i; mu[i] = -1;
}
for(int j = 1; j <= m && i * p[j] <= n; j ++){
v[i * p[j]] = true;
if(i % p[j]){
mu[i * p[j]] = -mu[i];
}
else {
mu[i * p[j]] = 0;
break;
}
}
}
for(int i = 2; i <= n; i ++){
mu[i] += mu[i - 1];
}
}
ll solve(int n, int m){
ll ans = 0;
for(int l = 1, r; l <= min(n, m); l = r + 1){
r = min(n / (n / l), m / (m / l));
ans += 1ll * (mu[r] - mu[l-1]) * (n / l) * (m / l);
}
return ans;
}
int main()
{
sieze(maxn-10);
int T; scanf("%d", &T);
while(T --){
int n, m, d; scanf("%d %d %d", &n, &m, &d);
ll ans = solve(n / d, m / d);
printf("%lld\n", ans);
}
return 0;
}