惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

I
Intezer
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
AWS News Blog
AWS News Blog
G
GRAHAM CLULEY
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
C
Cybersecurity and Infrastructure Security Agency CISA
N
News | PayPal Newsroom
T
Tenable Blog
Spread Privacy
Spread Privacy
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Secure Thoughts
P
Privacy International News Feed
IT之家
IT之家
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Engineering at Meta
Engineering at Meta
大猫的无限游戏
大猫的无限游戏
博客园_首页
GbyAI
GbyAI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
量子位
雷峰网
雷峰网
Apple Machine Learning Research
Apple Machine Learning Research
Hacker News: Ask HN
Hacker News: Ask HN
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
N
Netflix TechBlog - Medium
Martin Fowler
Martin Fowler
NISL@THU
NISL@THU
I
InfoQ
D
DataBreaches.Net
有赞技术团队
有赞技术团队
K
Kaspersky official blog
Security Latest
Security Latest
The Register - Security
The Register - Security
Hugging Face - Blog
Hugging Face - Blog
S
Security @ Cisco Blogs
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
H
Hackread – Cybersecurity News, Data Breaches, AI and More
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
AI
AI
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
Security Archives - TechRepublic
Security Archives - TechRepublic
N
News and Events Feed by Topic

OneCoder

【GESP】C++二级真题 luogu-B4553 [GESP202606 二级] 完全平方数计数 【GESP】C++一级真题 luogu-B4551 [GESP202606 一级] 去旅行 【GESP】C++一级真题 luogu-B4552 [GESP202606 一级] 交税 【NOIP】2000真题解析 luogu-P1023 税收与补贴问题(适合GESP四、五级以上练习) 【NOIP】2000真题解析 luogu-P1022 计算器的改良(适合GESP四、五级以上练习) 【CSP】CSP-X 2018真题 11的倍数 luogu-B4075 (适合GESP三级及以上考生练习) 【CSP】CSP-X 2018真题 统计成绩 luogu-B4074 (适合GESP二级及以上考生练习) 【CSP】CSP-X 2018真题 快递费用 luogu-B4073 (适合GESP二级及以上考生练习) 【CSP】CSP-X 2018真题 小明的照片 luogu-B4072 (适合GESP一级及以上考生练习) 【GESP】C++四级练习 luogu-P1138 第 k 小整数 【NOIP】2008真题解析 luogu-P1125 笨小猴 【信奥业余科普】C++ 的奇妙之旅 29:别让 TLE 和 MLE 偷走你的分——复杂度估算与数据范围速查 【信奥业余科普】C++ 的奇妙之旅 28:规范比赛代码的钥匙——文件操作与输入输出重定向(freopen) 【CSP】CSP-J 2023真题 公路 luogu-P9749 (适合GESP四级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 27:高效处理数据的利器——常用算法库(algorithm) 【CSP】CSP-J 2022真题 解密 luogu-P8814 (适合GESP四级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 26:高效的键值对——映射(map)与多重映射(multimap) 【CSP】CSP-J 2022真题 乘方 luogu-P8813 (适合GESP二级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 25:自动排序的利器——集合(set)与多重集合(multiset) 【CSP】CSP-J 2019真题 纪念品 luogu-P5662 (适合GESP六级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 24:拆解 deque——分段连续的双端队列 【信奥业余科普】C++ 的奇妙之旅 23:主动限制的艺术——栈(stack)与队列(queue)
【NOIP】2001真题解析 luogu-P1029 最大公约数和最小公倍数问题
OneCoder · 2026-06-24 · via OneCoder

NOIP 2001 普及组真题,考察 最大公约数(GCD)最小公倍数(LCM) 的数学性质。解题核心是利用 $\gcd(P, Q) \times \text{lcm}(P, Q) = P \times Q$ 的关系,将问题转化为枚举因数对并判断互质。适合GESP三级以上考生练习。题目难度⭐⭐,洛谷难度等级入门

luogu-P1029 [NOIP 2001 普及组] 最大公约数和最小公倍数问题

题目要求

题目描述

输入两个正整数 $x_0, y_0$,求出满足下列条件的 $P, Q$ 的个数:

  1. $P,Q$ 是正整数。
  2. 要求 $P, Q$ 以 $x_0$ 为最大公约数,以 $y_0$ 为最小公倍数。

试求:满足条件的所有可能的 $P, Q$ 的个数。

输入格式

一行两个正整数 $x_0, y_0$。

输出格式

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

输入输出样例 #1

输入 #1
输出 #1

说明/提示

$P,Q$ 有 $4$ 种:

  1. $3, 60$。
  2. $15, 12$。
  3. $12, 15$。
  4. $60, 3$。

对于 $100\%$ 的数据,$2 \le x_0, y_0 \le {10}^5$。

【题目来源】

NOIP 2001 普及组第二题


题目分析

这道题考察的是最大公约数(GCD)与最小公倍数(LCM)的基本性质,以及因数枚举互质判定的综合运用。

1. 关键数学性质

首先需要回顾一个基本公式:对于任意两个正整数 $P, Q$,有

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

题目要求 $\gcd(P, Q) = x_0$,$\text{lcm}(P, Q) = y_0$。由公式可得 $P \times Q = x_0 \times y_0$。

前提判断:$y_0$ 必须能被 $x_0$ 整除(因为 $\text{lcm}(P,Q)$ 一定是 $\gcd(P,Q)$ 的倍数)。如果 $y_0 \mod x_0 \neq 0$,则不存在满足条件的 $P, Q$,直接输出 $0$。

2. 变量替换与问题简化

令 $P = x_0 \times a$,$Q = x_0 \times b$。由于 $\gcd(P, Q) = x_0$,所以 $a, b$ 必须互质,即 $\gcd(a, b) = 1$。

同时由 $\text{lcm}(P, Q) = y_0$,可推出 $a \times b = y_0 / x_0$。记 $k = y_0 / x_0$。

这样问题转化为:求 $k$ 的因数对 $(a, b)$ 的个数,满足 $a \times b = k$ 且 $\gcd(a, b) = 1$。注意 $(a, b)$ 和 $(b, a)$ 算两种不同方案(因为对应不同的 $P, Q$)。

3. 枚举因数

从 $1$ 到 $\sqrt{k}$ 枚举 $a$,若 $k \mod a = 0$,则 $b = k / a$。然后判断 $\gcd(a, b)$ 是否等于 $1$:

  • 如果 $a \neq b$(即 $a \neq \sqrt{k}$),则 $(a, b)$ 和 $(b, a)$ 是两种方案,计数加 $2$。
  • 如果 $a = b$(即 $k$ 是完全平方数且 $a = \sqrt{k}$),则只有一种方案,计数加 $1$。但此时 $\gcd(a, a) = a$,只有 $a = 1$ 时才互质,即 $k = 1$ 的特殊情况。

复杂度分析:

  • 时间复杂度:$O(\sqrt{y_0 / x_0} \times \log(y_0 / x_0))$,其中枚举因数为 $O(\sqrt{k})$,每次 GCD 计算为 $O(\log k)$。
  • 空间复杂度:$O(1)$,只使用常数个变量。

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <algorithm>
#include <iostream>

// 辗转相除法求最大公约数
int gcd(int a, int b) {
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

int main() {
    int x0, y0;
    std::cin >> x0 >> y0;

    // 前提判断:最小公倍数必须是最大公约数的倍数
    if (y0 % x0 != 0) {
        std::cout << 0 << std::endl;
        return 0;
    }

    int k = y0 / x0; // 将问题转化为在 k 的因数中寻找互质对
    int count = 0;

    // 枚举 k 的因数,只需枚举到 sqrt(k)
    for (int a = 1; a * a <= k; a++) {
        if (k % a == 0) {
            int b = k / a;
            // 判断因数对 (a, b) 是否互质
            if (gcd(a, b) == 1) {
                if (a == b) {
                    count += 1; // a == b 时只有一种方案
                } else {
                    count += 2; // (a, b) 和 (b, a) 是两种不同方案
                }
            }
        }
    }

    std::cout << count << std::endl;

    return 0;
}

更直接的思路

上面的方法通过变量替换 $a = P / x_0$、$b = Q / x_0$ 将问题转化为”求 $k$ 的互质因数对”,虽然数学上更优雅,但理解起来多了一层抽象。

一种更直观的方法是:直接枚举 $P$,由 $P \times Q = x_0 \times y_0$ 算出 $Q$,然后验证 $\gcd(P, Q) = x_0$ 是否成立。

具体步骤:

  1. 前提判断:$y_0 \mod x_0 \neq 0$ 则无解。
  2. 枚举 $P$:$P$ 必须是 $x_0$ 的倍数(因为 $\gcd(P, Q) = x_0$ 意味着 $x_0 \mid P$),所以令 $P = x_0, 2x_0, 3x_0, \ldots$。
  3. 计算 $Q$:由 $P \times Q = x_0 \times y_0$,得 $Q = x_0 \times y_0 / P$。需要 $P \mid (x_0 \times y_0)$ 且 $Q$ 为正整数。
  4. 验证:检查 $\gcd(P, Q) = x_0$ 是否成立。
  5. 优化枚举范围:只需枚举 $P \le Q$(即 $P^2 \le x_0 \times y_0$),找到一对后根据 $P$ 是否等于 $Q$ 计数 $1$ 或 $2$。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <algorithm>
#include <iostream>

// 辗转相除法求最大公约数
int gcd(int a, int b) {
    while (b != 0) {
        int temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}

int main() {
    int x0, y0;
    std::cin >> x0 >> y0;

    // 前提判断:最小公倍数必须是最大公约数的倍数
    if (y0 % x0 != 0) {
        std::cout << 0 << std::endl;
        return 0;
    }

    long long product = (long long)x0 * y0; // P * Q = x0 * y0
    int count = 0;

    // 直接枚举 P,P 必须是 x0 的倍数
    for (long long p = x0; p * p <= product; p += x0) {
        if (product % p == 0) {
            long long q = product / p;
            // 直接验证 gcd(P, Q) 是否等于 x0
            if (gcd(p, q) == x0) {
                if (p == q) {
                    count += 1;
                } else {
                    count += 2;
                }
            }
        }
    }

    std::cout << count << std::endl;

    return 0;
}

这种写法不需要做变量替换,思路更直白:枚举 → 计算 → 验证,更容易在考场上快速实现。


所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

"luogu-"系列题目可在洛谷题库进行在线评测。

"bcqm-"系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号

GESP/CSP 认证学习微信公众号