Zap
题意
对于给定的整数a,b和d,有多少正整数对x,y,满足 x ≤ a , y ≤ b x\leq a,y\leq b x≤a,y≤b,并且 g c d ( x , y ) = d gcd(x,y)=d gcd(x,y)=d
分析
要求 x ≤ a , y ≤ b x\leq a,y\leq b x≤a,y≤b,并且 g c d ( x , y ) = d gcd(x,y)=d gcd(x,y)=d,先把x和y映射一下,令 x ′ = ⌊ x d ⌋ x'=\lfloor \frac{x}{d} \rfloor x′=⌊dx⌋, y ′ = ⌊ y d ⌋ y'=\lfloor \frac{y}{d} \rfloor y′=⌊dy⌋,那么就变成了 x ′ ≤ ⌊ a d ⌋ , y ′ ≤ ⌊ b d ⌋ x' \leq \lfloor \frac{a}{d} \rfloor,y' \leq \lfloor \frac{b}{d} \rfloor x′≤⌊da⌋,y′≤⌊db⌋, g c d ( x ′ , y ′ ) = 1 gcd(x',y')=1 gcd(x′,y′)=1,再令 a ′ = ⌊ a d ⌋ , b ′ = ⌊ b d ⌋ a'=\lfloor \frac{a}{d} \rfloor,b'=\lfloor \frac{b}{d} \rfloor a′=⌊da⌋,b′=⌊db⌋,最终就是 x ′ ≤ a ′ , y ′ ≤ b ′ , g c d ( x ′ , y ′ ) = 1 x'\leq a',y' \leq b',gcd(x',y')=1 x′≤a′,y′≤b′,gcd(x′,y′)=1
根据容斥原理可知,答案就是 a ′ b ′ a'b' a′b′-gcd=2时-gcd=3时+gcd=6时…
再根据数列分块知识, ⌊ a x ⌋ \lfloor \frac{a}{x} \rfloor ⌊xa⌋中结果相同的最大的 x = ⌊ a ⌊ a x ⌋ ⌋ x=\lfloor \frac{a}{\lfloor \frac{a}{x} \rfloor} \rfloor x=⌊⌊xa⌋a⌋,可知时间复杂度为 O ( n ) O(\sqrt n) O(n)
所以要预处理出莫比乌斯函数的前缀和,再分别计算出每一段值相等时最大的右边界
m
i
n
(
a
′
,
b
′
,
⌊
a
′
⌊
a
′
l
⌋
⌋
,
⌊
b
′
⌊
b
′
l
⌋
⌋
)
min({a',b',\lfloor \frac{a'}{\lfloor \frac{a'}{l} \rfloor} \rfloor, \lfloor \frac{b'}{\lfloor \frac{b'}{l} \rfloor} \rfloor})
min(a′,b′,⌊⌊la′⌋a′⌋,⌊⌊lb′⌋b′⌋),相等的值分别就是
⌊
a
′
l
⌋
\lfloor \frac{a'}{l} \rfloor
⌊la′⌋和
⌊
b
′
l
⌋
\lfloor \frac{b'}{l} \rfloor
⌊lb′⌋
a
n
s
=
a
′
b
′
+
∑
l
=
2
m
i
n
(
a
′
,
b
′
)
(
μ
(
r
)
−
μ
(
l
−
1
)
)
⌊
a
′
l
⌋
⌊
b
′
l
⌋
\begin{align} ans=a'b'+\sum_{l=2}^{min(a',b')}(\mu(r)-\mu(l-1))\lfloor \frac{a'}{l} \rfloor \lfloor \frac{b'}{l} \rfloor \end{align}
ans=a′b′+l=2∑min(a′,b′)(μ(r)−μ(l−1))⌊la′⌋⌊lb′⌋
AC代码
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int cnt, prime[1000010], mobius[1000010], pre[1000010];
bool vis[1000010];
void init() {
mobius[1] = 1;
for (int i = 2; i <= 1000000; i++) {
if (!vis[i]) {
prime[++cnt] = i;
mobius[i] = -1;
}
for (int j = 1; j <= cnt && i * prime[j] <= 1000000; j++) {
vis[i * prime[j]] = true;
if (i % prime[j] == 0) {
mobius[i * prime[j]] = 0;
break;
}
mobius[i * prime[j]] = mobius[i] * mobius[prime[j]];
}
}
for (int i = 1; i <= 1000000; i++) {
pre[i] = mobius[i] + pre[i - 1];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int q;
cin >> q;
while (q--) {
int a, b, d;
cin >> a >> b >> d;
LL ans = 0;
a /= d;
b /= d;
ans = 1LL * a * b;
int n = min(a, b);
for (int l = 2, r; l <= n; l = r + 1) {
r = min({n, a / (a / l), b / (b / l)});
ans = ans + 1LL * (pre[r] - pre[l - 1]) * (a / l) * (b / l);
}
cout << ans << '\n';
}
return 0;
}