[特殊字符]【算法日记 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 )。

🏆 结语

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

相关推荐
菜菜的顾清寒2 小时前
力扣HOT100(44)对称二叉树
数据结构·算法·leetcode
吃好睡好便好2 小时前
矩阵的左乘和右乘
人工智能·学习·线性代数·算法·matlab·矩阵
我命由我123452 小时前
SEO 与 GEO 极简理解
java·linux·运维·开发语言·学习·算法·运维开发
月光刺眼2 小时前
🎶二分 · 双指针 · 滑动窗口 · 螺旋矩阵:数组算法四题拆解
javascript·算法
海清河晏1112 小时前
字符串匹配:BF算法与KMP算法
数据结构·算法·visual studio
wandertp2 小时前
对信号处理及滤波器的理解---基于robomaster机器人嵌入式控制系统
arm开发·stm32·算法·信号处理
z小猫不吃鱼2 小时前
15 InstructGPT 论文精读:SFT + RLHF 如何让模型听懂指令?
人工智能·深度学习·算法·机器学习·语言模型·自然语言处理·gpt-3
见合八方3 小时前
【滤波器】热调谐FP滤波器
人工智能·算法
古城小栈3 小时前
cargo-pprof:Rust性能调优
人工智能·算法·rust
x_xbx3 小时前
LeetCode:543. 二叉树的直径
算法·leetcode·职场和发展