1 条题解
-
0
问题分析
我们需要计算满足以下条件的正整数对 的个数:
关键转化
令 , ,则原条件等价于:
问题转化为:计算在 $[1, \lfloor a/d \rfloor] \times [1, \lfloor b/d \rfloor]$ 范围内,互质对的个数。
莫比乌斯反演
定义
设 , ,我们要求:
应用莫比乌斯反演
利用莫比乌斯函数的性质:
因此:
$$\sum_{i=1}^A \sum_{j=1}^B [\gcd(i,j) = 1] = \sum_{i=1}^A \sum_{j=1}^B \sum_{d|\gcd(i,j)} \mu(d) $$交换求和顺序:
$$= \sum_{d=1}^{\min(A,B)} \mu(d) \sum_{i=1}^{\lfloor A/d \rfloor} \sum_{j=1}^{\lfloor B/d \rfloor} 1 = \sum_{d=1}^{\min(A,B)} \mu(d) \cdot \left\lfloor \frac{A}{d} \right\rfloor \cdot \left\lfloor \frac{B}{d} \right\rfloor $$算法优化
数论分块
直接计算 $\sum_{d=1}^n \mu(d) \cdot \lfloor A/d \rfloor \cdot \lfloor B/d \rfloor$ 是 的,但我们可以利用数论分块优化到 。
观察 和 的值在连续的 区间内是常数。对于区间 ,有:
区间的右端点为:
$$r = \min\left( \left\lfloor \frac{A}{\lfloor A/l \rfloor} \right\rfloor, \left\lfloor \frac{B}{\lfloor B/l \rfloor} \right\rfloor \right) $$前缀和预处理
预处理莫比乌斯函数的前缀和:
for (int i = 1; i < N; i++) { mobius[i] += mobius[i - 1]; }代码解析
莫比乌斯函数计算
void make_mobius(void) { // 线性筛预处理最小质因子 for (int i = 2; i < N; i++) { if (prime[i] == 0) { for (int j = i; j < N; j += i) { prime[j] = i; } } } mobius[1] = 1; // 递推计算莫比乌斯函数 for (int i = 2; i < N; i++) { if (i % (prime[i]*prime[i]) == 0) { mobius[i] = 0; // 有平方因子 } else { mobius[i] = -mobius[i / prime[i]]; // 积性函数性质 } } // 计算前缀和 for (int i = 1; i < N; i++) { mobius[i] += mobius[i - 1]; } }查询处理
void test() { int a, b; cin >> a >> b; int d; cin >> d; a /= d; // A = floor(a/d) b /= d; // B = floor(b/d) int n = min(a, b); int s = 0; int l = 1; int r = 1; // 数论分块 while (l <= n) { r = min(a / (a / l), b / (b / l)); // 利用前缀和计算区间和 s += (mobius[r] - mobius[l - 1]) * (a / l) * (b / l); l = r + 1; } cout << s << "\n"; }复杂度分析
- 预处理:,其中
- 每次查询:
- 总复杂度:,其中 是查询次数
样例验证
样例1:
4 5 2- 计算 $\sum_{d=1}^2 \mu(d) \cdot \lfloor 2/d \rfloor \cdot \lfloor 2/d \rfloor$
- :
- :
- 结果: ✓
样例2:
6 4 3- 计算 $\sum_{d=1}^1 \mu(d) \cdot \lfloor 2/d \rfloor \cdot \lfloor 1/d \rfloor$
- :
- 结果: ✓
总结
本题通过莫比乌斯反演将数论问题转化为可高效计算的形式,结合数论分块和前缀和优化,实现了对大量查询的高效处理。这是数论中经典的技巧组合,在解决涉及 计数的问题时非常有效。
- 1
信息
- ID
- 5124
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者