[特殊字符]【算法日记 14】数论入门神题:最大公约数与最小公倍数的“乘积守恒定律”

🚀【算法日记 14】数论入门神题:最大公约数与最小公倍数的"乘积守恒定律"

📍 题目背景:洛谷 P1029 [NOIP2001 普及组]

这是一道来自 NOIP 2001 年的经典普及组题目。题目要求给定两个正整数 x0x_0x0 (最大公约数) 和 y0y_0y0 (最小公倍数),求满足条件的整数对 (P,Q)(P, Q)(P,Q) 的个数。
【输入格式】

一行两个正整数 x0,y0x_0, y_0x0,y0。

【输出格式】

一行一个数,表示求出满足条件的 P,QP, QP,Q 的个数。

【输入输出样例】
输入:

text 复制代码
3 60

输出:

text 复制代码
4

【说明/提示】
P,QP, QP,Q 有 4 种:
3, 60
15, 12
12, 15
60, 3

对于 100% 的数据,2≤x0,y0≤1052 \le x_0, y_0 \le 10^52≤x0,y0≤105。


✨ 核心数学逻辑:乘积守恒定律

在处理这类题目时,最核心的物理规律是:
任意两个正整数 PPP 和 QQQ 的乘积,等于它们的最大公约数(GCD)与最小公倍数(LCM)的乘积。

P×Q=gcd(P,Q)×lcm(P,Q)P \times Q = \text{gcd}(P, Q) \times \text{lcm}(P, Q)P×Q=gcd(P,Q)×lcm(P,Q)

🎯 降维打击思路:

  1. 已知条件 :我们已知 x0=gcd(P,Q)x_0 = \text{gcd}(P, Q)x0=gcd(P,Q) 和 y0=lcm(P,Q)y_0 = \text{lcm}(P, Q)y0=lcm(P,Q)。
  2. 转换方程 :P×Q=x0×y0P \times Q = x_0 \times y_0P×Q=x0×y0。
  3. 减少变量 :我们不需要枚举 PPP 和 QQQ。只需要枚举 PPP,那么 QQQ 就可以直接通过 x0×y0P\frac{x_0 \times y_0}{P}Px0×y0 算出来!
  4. 确定范围
    • PPP 必须是 x0x_0x0 的倍数,所以起始值是 x0x_0x0,步长是 x0x_0x0。
    • PPP 最大不会超过 y0y_0y0。

💻 最终满分 AC 代码(已排雷)

这段代码解决了初学者最容易踩的两个坑:整型溢出取模判断

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 🚀 竞赛极速读写引擎
    ios::sync_with_stdio(false);
    cin.tie(0);

    long long x0, y0;
    if (!(cin >> x0 >> y0)) return 0;

    // 💣 避坑指南 1:y0 必须能被 x0 整除,否则无解
    if (y0 % x0 != 0) {
        cout << 0 << "\n";
        return 0;
    }

    long long count = 0;
    // 💣 避坑指南 2:提前存储乘积,防止在循环中重复计算,且必须用 long long
    long long prod = x0 * y0; 

    // 🚀 性能优化:步长设为 x0,极大减少循环次数
    for (long long p = x0; p <= y0; p += x0) {
        // 💣 避坑指南 3:必须使用 % 判断是否能整除,不能用 /
        if (prod % p == 0) {
            long long q = prod / p;
            
            // 🚀 核心判定:计算出的 P 和 Q 的最大公约数必须等于 x0
            if (__gcd(p, q) == x0) {
                count++;
            }
        }
    }

    cout << count << "\n";
    return 0;
}

💣 首席质检员的避坑总结

  1. long long 是保命符 :题目范围虽然是 10510^5105,但 x0×y0x_0 \times y_0x0×y0 会达到 101010^{10}1010,远超 int 的 21 亿上限。不写 long long 必炸!
  2. __gcd(a, b) 核武器 :C++ <algorithm><numeric> 库自带的这个函数效率极高,不需要自己手写辗转相除法。
  3. 整除判断的低级错误 :记住,判断"能否整除"用的是 a % b == 0,而不是 a / b == 0。这是新手最容易在键盘上滑手的地方。
  4. 对称性优化(进阶) :如果你想更进一步,可以只枚举到 x0×y0\sqrt{x_0 \times y_0}x0×y0 ,然后每次 count += 2。这能把时间复杂度从 O(N)O(N)O(N) 降到 O(N)O(\sqrt{N})O(N )。

🏆 结语

这道题教会了我们:不要盲目暴力,先列数学方程。 在算法竞赛中,数学推导永远是写代码之前最高效的"外挂"。

相关推荐
保卫大狮兄1 小时前
一文讲清:仓库管理最核心的10个公式
人工智能·算法·仓库管理
翻身的咸鱼ing2 小时前
常用代码知识
算法·深度优先·哈希算法
feifeigo1232 小时前
自适应大邻域搜索(ALNS)算法的MATLAB 实现
开发语言·算法·matlab
RH2312113 小时前
2026.4.29数据结构 直接插入排序&&希尔排序
数据结构·算法·排序算法
搬砖的小码农_Sky3 小时前
AI Agent:OpenClaw的算法架构
人工智能·算法·ai·架构·人机交互·agi
热心网友俣先生3 小时前
2026年金地杯A题解题思路
算法
科研前沿3 小时前
SpaceOS™空间计算底座与五大自研引擎,实现多项关键技术突破
大数据·运维·人工智能·算法·重构
昵称小白3 小时前
C++ 刷题语法速查
c++·算法
JQLvopkk3 小时前
C# 工业级数据可视化:用ScottPlot让10万个点流畅显示的实战秘籍
人工智能·算法·机器学习