分析
等价于求
∑
i
=
1
n
∑
j
=
1
m
(
(
gcd
(
i
,
j
)
−
1
)
⋅
2
+
1
)
\sum_{i = 1}^{n}\sum_{j = 1}^{m}((\gcd(i,j) - 1) \cdot2+1)
∑i=1n∑j=1m((gcd(i,j)−1)⋅2+1)
化简
∑
i
=
1
n
∑
j
=
1
m
(
2
⋅
gcd
(
i
,
j
)
−
1
)
=
∑
i
=
1
n
∑
j
=
1
m
2
⋅
gcd
(
i
,
j
)
−
n
⋅
m
=
2
⋅
∑
i
=
1
n
∑
j
=
1
m
g
c
d
(
i
,
j
)
−
n
⋅
m
\sum_{i = 1}^{n}\sum_{j = 1}^{m}( 2\cdot\gcd(i,j) - 1) = \sum_{i = 1}^{n}\sum_{j = 1}^{m} 2\cdot\gcd(i,j) - n\cdot m = 2\cdot\sum_{i = 1}^{n}\sum_{j = 1}^{m} gcd(i,j) - n\cdot m
∑i=1n∑j=1m(2⋅gcd(i,j)−1)=∑i=1n∑j=1m2⋅gcd(i,j)−n⋅m=2⋅∑i=1n∑j=1mgcd(i,j)−n⋅m
因为
i
d
=
1
∗
φ
id = 1 * φ
id=1∗φ
所以原式化为
2
⋅
∑
i
=
1
n
∑
j
=
1
m
∑
k
∣
gcd
(
i
,
j
)
φ
(
k
)
−
n
⋅
m
=
2
⋅
∑
k
=
1
min
(
n
,
m
)
φ
(
k
)
⋅
⌊
n
k
⌋
⋅
⌊
m
k
⌋
−
n
⋅
m
2\cdot\sum_{i = 1}^{n}\sum_{j = 1}^{m} \sum_{k | \gcd(i,j)}φ(k) - n\cdot m = 2\cdot \sum_{k =1}^{\min(n,m)}φ(k)\cdot\lfloor\dfrac{n}{k}\rfloor\cdot\lfloor\dfrac{m}{k}\rfloor - n\cdot m
2⋅∑i=1n∑j=1m∑k∣gcd(i,j)φ(k)−n⋅m=2⋅∑k=1min(n,m)φ(k)⋅⌊kn⌋⋅⌊km⌋−n⋅m
于是可以用
O
(
n
)
O(n)
O(n) 或者
O
(
n
log
n
)
O(n\log{n})
O(nlogn) 的时间复杂度求
φ
φ
φ 的前缀和,用
O
(
n
)
O(\sqrt{n})
O(n) 的时间整除分块求解。
代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, v[MAXN];
long long prime[MAXN], phi[MAXN], sph[MAXN], cnt = 0;
void eular (int x) {
phi[1] = 1;
memset (v, 0, sizeof (v));
for (int q = 2; q <= x; ++q) {
if (! v[q]) {
prime[++ cnt] = q;
phi[q] = q - 1;
}
for (int w = 1; w <= cnt && prime[w] * q <= x; ++w) {
if (prime[w] * q > x) break;
v[prime[w] * q] = 1;
phi[prime[w] * q] = phi[q] * phi[prime[w]];
if ((q % prime[w]) == 0) {
phi[prime[w] * q] = phi[q] * prime[w];
break;
}
}
}
sph[0] = 0;
for (int q = 1; q <= x; ++q) {
sph[q] = sph[q - 1] + phi[q];
}
}
long long solve (long long x, long long y) {
long long ans = 0;
if (x < y) swap (x, y);
for (int l = 1, r; l <= y; l = r + 1) {
r = min (x / (x / l), y / (y / l));
ans += (long long) (sph[r] - sph[l - 1]) * (x / l) * (y / l);
}
return ans;
}
int main () {
eular (100000);
scanf ("%lld %lld", &n, &m);
if (n < m) swap (n, m);
long long sum = solve (n, m);
sum = (long long) 2 * sum - (long long)n * m;
printf ("%lld\n", sum);
return 0;
}