进阶 · 数位
阿姆斯特朗数
153 出名是因为 1³ + 5³ + 3³ = 153。推广一下:先数位数,再把每位升到那个次方求和。数位求和是热身。
一句话答案一个 n 位数如果每位数字的 n 次方之和等于它本身,就是阿姆斯特朗数(153 = 1³ + 5³ + 3³)—— 先数位数,再遍历一遍累加幂。
题目
输入: 一个整数 N(1 ≤ N ≤ 10⁶)。
输出: 若 N 是阿姆斯特朗数输出 yes,否则输出 no。
样例:
| 输入 | 输出 |
|---|---|
153 | yes |
123 | no |
9474 | yes |
你的解答
「运行我的输入」用的自定义输入
判题在浏览器本地运行。死循环会在 3 秒后被自动中断 —— 但还是确保每个循环都有出口。代码随打随存。
卡住了?提示
提示 1 — 两遍扫描
第一遍:把 n 拷到临时变量,不断除以 10 直到为 0,顺便数出位数 d。第二遍:用 % 10 取每位,升到 d 次方(一个内层小循环),累加。
提示 2 — 不需要 pow()
JSCPP 没有 <cmath>,所以用循环求幂(把 digit 自乘 d 次)。累加和用 long long —— 999999 有 6 位,9⁶ × 6 会超过 32 位 int。
题解(先自己试试!)
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int t = n, d = 0;
while (t) { d++; t /= 10; }
t = n;
long long sum = 0;
while (t) {
int dig = t % 10;
long long p = 1;
for (int i = 0; i < d; i++) p *= dig;
sum += p;
t /= 10;
}
cout << (sum == n ? "yes" : "no") << endl;
return 0;
}
进阶:打印 1000000 以下所有阿姆斯特朗数,或者单独处理一位数的边界(每个一位数都是)。相关:数位求和、最小公倍数。
深度解析
为什么这样做对
要先知道位数才能算,所以自然的结构是两遍扫描:一遍测量,一遍求和。把问题拆成「我得先知道什么」,才是能带走的技能。
代价
O(d) 时间(d 是位数,这里最多 7 位),O(1) 空间。内层求幂每位跑 d 次,总共 d²,依然微不足道。
常见错法
- 想用
<cmath>的pow(digit, d)—— JSCPP 没有这个头文件,得自己写一个三行的连乘循环。 - 把累加和放在
int里 —— 9⁶ × 6 = 3188646 还没事,但 7 位数就会顶破 int 上限;用long long不花任何代价。
下一步
循环这个判断,打印一百万以内的所有阿姆斯特朗数(只有 88 个)。最小公倍数是同一套「数位 + gcd」工具箱的另一半。
记住这两句
- 先数位数,幂次取决于它。
- 浏览器引擎里没有
<cmath>,三行循环就能代替 pow()。
🐞 这段是错的 —— 点开,亲手让它挂一次
永远按三次方算 —— 153 对,9474 就错了(四位数要四次方)
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int t = n, sum = 0;
while (t) {
int d = t % 10;
sum += d * d * d; // hard-coded cube: only works for 3-digit numbers
t /= 10;
}
cout << (sum == n ? "yes" : "no") << endl;
return 0;
}