题目大意:
题目链接
给定N,M问有多少对
g
c
d
(
i
,
j
)
gcd(i,j)
gcd(i,j)为质数
1
≤
i
≤
N
,
1
≤
j
≤
M
1\le i \le N,1 \le j \le M
1≤i≤N,1≤j≤M
解题思路:
通过枚举质数p,来找有多少对使
g
c
d
(
i
,
j
)
=
=
p
gcd(i,j)==p
gcd(i,j)==p
由P2522 [HAOI2011]Problem b,式子可变换为
∑
p
∑
d
=
1
μ
(
d
)
⌊
n
p
d
⌋
⌊
m
p
d
⌋
\sum_p\sum_{d=1}\mu(d)\left \lfloor \frac n{pd} \right \rfloor\left \lfloor \frac m{pd} \right \rfloor
∑p∑d=1μ(d)⌊pdn⌋⌊pdm⌋
令T=pd
∑ p ∑ d = 1 μ ( d ) ⌊ n p d ⌋ ⌊ m p d ⌋ = ∑ p ∑ d = 1 μ ( T p ) ⌊ n T ⌋ ⌊ m T ⌋ \sum_p\sum_{d=1}\mu(d)\left \lfloor \frac n{pd} \right \rfloor\left \lfloor \frac m{pd} \right \rfloor=\sum_p\sum_{d=1}\mu(\frac Tp)\left \lfloor \frac n{T} \right \rfloor\left \lfloor \frac m{T} \right \rfloor ∑p∑d=1μ(d)⌊pdn⌋⌊pdm⌋=∑p∑d=1μ(pT)⌊Tn⌋⌊Tm⌋
令
∑
T
=
1
F
[
T
]
=
∑
p
∑
d
=
1
μ
(
T
p
)
\sum_{T=1}F[T]=\sum_p\sum_{d=1}\mu(\frac Tp)
∑T=1F[T]=∑p∑d=1μ(pT)
(为了拟合数论分块,所以我们寻找式子把前面的未知量替换成只与T有关)
原式 = ∑ T = 1 F [ T ] ⌊ n T ⌋ ⌊ m T ⌋ =\sum_{T=1}F[T]\left \lfloor \frac n{T} \right \rfloor\left \lfloor \frac m{T} \right \rfloor =∑T=1F[T]⌊Tn⌋⌊Tm⌋
求 F [ T ] F[T] F[T]用埃拉托斯特尼筛法来求即可
AC代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 1e7 + 10;
ll Q, n, m, cnt, ans;
ll p[maxn], vis[maxn], mu[maxn], T[maxn];
void init() {
vis[1] = mu[1] = 1;
for (ll i = 2; i < maxn; i++) {
if (!vis[i]) p[++cnt] = i, mu[i] = -1;
for (ll j = 1; j <= cnt && 1ll * i * p[j] < maxn; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0) {
mu[p[j] * i] = 0;
break;
}
else {
mu[i * p[j]] = -mu[i];
}
}
}
for (ll i = 1; i <= cnt; i++)
for (ll j = p[i]; j < maxn; j += p[i])
T[j] += mu[j / p[i]];
for (ll i = 1; i < maxn; i++) T[i] += T[i - 1];//求前缀和
}
ll cal() {
ll res = 0;
for (ll i = 1, j; i <= min(n, m); i = j + 1) {
j = min(n / (n / i), m / (m / i));//取较小的那个
res += (T[j] - T[i - 1]) * (n / i) * (m / i);
}
return res;
}
int main() {
init();
cin >> Q;
while (Q--) {
cin >> n >> m;
ans = cal();
cout << ans << endl;
}
}