史密斯数是合数且其各位数字之和等于所有质因数(含重复)的各位数字之和;判定需三步:验证合数、完全分解质因数(保留重数)、分别计算并比较数字和。

什么是史密斯数?先看判定逻辑
史密斯数是合数(非质数且大于1),且其各位数字之和等于它所有**质因数**(含重复)的各位数字之和。注意两点:必须是合数;质因数要按重数展开,比如 4 = 2 × 2,质因数数字和是 2 + 2 = 4,不是 2。
所以判断分三步:检查是否为合数 → 分解质因数(带重数)→ 分别算数字和并比较。
如何高效分解质因数并保留重复?
对 long long 范围内的数(如 10^12),试除到 sqrt(n) 即可。关键点在于:每次找到一个质因子 p,就不断用 n /= p,把所有该因子的幂次都提取出来,并把每个 p 都加入因子列表(不是只加一次)。
- 循环从
i = 2开始,直到i * i - 若
n % i == 0,则反复除以i,每除一次就把i推入factors向量 - 最后若
n > 1,说明剩余的n本身是质数,也要加入factors
例如 n = 999:分解得 3, 3, 3, 37,数字和为 3+3+3+3+7 = 19;原数各位和为 9+9+9 = 27 → 不是史密斯数。
立即学习“C++免费学习笔记(深入)”;
数字和怎么算?别用字符串转换
对整数求各位数字和,用取模和整除最直接、无开销:
int digit_sum(long long x) {
int s = 0;
while (x) {
s += x % 10;
x /= 10;
}
return s;
}注意:传入负数要先取绝对值;0 要单独处理(但史密斯数定义中 n > 1,可忽略)。
常见错误是把质因数当成“唯一质因子”去算和(比如对 24 = 2^3 × 3 只加 2+3),实际应加 2+2+2+3 = 9。
完整判定函数的关键边界与陷阱
容易漏掉的几个点:
-
is_prime()或is_composite()必须显式排除1和质数:史密斯数要求是合数,所以4是最小可能值 - 质因数分解后,若因子列表为空(理论上不会,因已排除质数),或只有一个因子且等于原数(即原数本身是质数),直接返回
false -
long long输入时,sqrt(n)要用sqrtl(n)或(long long)sqrt((double)n) + 1防止浮点误差 - 性能上,最坏情况(如大质数附近的大合数)仍接近
O(√n),对10^12是可行的(约10^6次操作)
真正难处理的是像 2050918644 这类数——它有多个小质因子,但最后剩下一个大质因子(如 1000000007),此时分解不慢,但数字和计算必须严格对应重数。


















