中 · 数论
最小公倍数
你在最大公约数里已经写过 gcd。最小公倍数就是 a / gcd(a,b) * b —— 但顺序很关键,否则乘积会溢出。
一句话答案最小公倍数是 a / gcd(a, b) * b —— 先除后乘:10⁴ 这个量级乘起来还不会溢出,但正是这个习惯让输入变大时依然正确。
题目
输入: 两行,各一个整数:a 然后 b(1 ≤ a, b ≤ 10000)。
输出: 它们的最小公倍数。
样例:
| 输入 | 输出 |
|---|---|
4 | 12 |
3 | 15 |
12 | 36 |
你的解答
「运行我的输入」用的自定义输入
判题在浏览器本地运行。死循环会在 3 秒后被自动中断 —— 但还是确保每个循环都有出口。代码随打随存。
卡住了?提示
提示 1 — 公式
lcm(a,b) = a * b / gcd(a,b)。但写成 a / gcd(a,b) * b —— 先除让中间值更小,在本题范围内不会溢出 32 位 int。
提示 2 — 相等的数
若 a == b,答案就是 a —— 公式同样成立,无需特判。注意运算顺序:a / gcd * b 是整数运算,先除后乘。
题解(先自己试试!)
#include <iostream>
using namespace std;
long long gcd(long long a, long long b) {
while (b) {
long long t = a % b;
a = b;
b = t;
}
return a;
}
int main() {
long long a, b;
cin >> a >> b;
cout << a / gcd(a, b) * b << endl;
return 0;
}
可以进阶了:求两个边界之间有多少个 k 的倍数,或者先用 gcd 约分再用 lcm 通分。下一关:阿姆斯特朗数。
深度解析
为什么这样做对
a * b = gcd(a,b) * lcm(a,b) 这一条恒等式就是全部窍门 —— 有了 gcd,lcm 只差一次除法。不用枚举倍数,也不用猜。
代价
O(log min(a,b)) 时间,和欧几里得 gcd 一样。O(1) 空间。写成 a / gcd * b 能让中间值在本题范围内留在 32 位以内。
常见错法
- 写成
a * b / gcd(a,b)是先乘后除,a、b 一大中间值就溢出 int,答案变成负数。 - gcd 里把
a = b; b = a % b的顺序写反、又没先存余数,可能死循环或返回 0 —— 先把a % b存进临时变量再赋值才稳。
下一步
同一个函数换个用法:分子分母同除 gcd 就能约分。阿姆斯特朗数把「数位 + 幂」的想法反过来用。
记住这两句
- lcm(a,b) = a / gcd(a,b) * b —— 先除后乘。
- 欧几里得 gcd 是可复用的工具,多数数论题离它只有一次调用。
🐞 这段是错的 —— 点开,亲手让它挂一次
印的是乘积不是最小公倍数 —— 4 6 输出 24,判题要的是 12
#include <iostream>
using namespace std;
int main() {
long long a, b;
cin >> a >> b;
cout << a * b << endl; // product, not lcm
return 0;
}