合数的阶乘指某个合数n(n≥4)的阶乘n!,即判断x是否等于某合数的阶乘;需预计算4!至20!中所有合数n对应的n!并查表,排除质数阶乘和溢出值。

什么是合数的阶乘,先搞清定义再写代码
合数的阶乘不是数学标准术语,实际是指“某个合数 n 的阶乘 n!”,即判断一个正整数 x 是否等于某个合数的阶乘(如 4! = 24、6! = 720、8! = 40320 等)。注意:不能是质数的阶乘(如 2!、3!、5! 虽然存在,但不符合“合数的阶乘”这一条件)。
所以问题本质是:给定正整数 x,是否存在合数 n ≥ 4(最小合数是 4),使得 n! == x?
直接预计算比实时分解更可靠
阶乘增长极快:10! = 3628800,13! = 6227020800 已超 int 范围,21! 就远超 uint64_t。因此对输入 x 做暴力试除或质因数分解去反推阶乘来源,既慢又易出错(比如 120 可能被误判为 5!,但 5 是质数,不合法)。
更稳的做法是:预生成所有「合数的阶乘」值,存入集合,查表即可。合数从 4 开始,算到 n! 超出 uint64_t 上限为止:
// 合数列表:4, 6, 8, 9, 10, 12, 14, 15, 16, ... // 但注意:阶乘只依赖 n 本身,不是 n 的因子;我们只要 n 是合数,就计算 n! // 实际只需遍历 n = 4, 5, 6, ...,跳过质数
实操建议:
- 用
std::set<uint64_t></uint64_t>或std::unordered_set<uint64_t></uint64_t>存储合法值 - 循环中用
uint64_t fact = 1累乘,每次乘前检查是否溢出(fact > ULLONG_MAX / n) - 对每个
n先用简单试除法判断是否为合数(n > 1 && !is_prime(n)),is_prime只需试到sqrt(n) -
12!是 479001600,14!是 87178291200,16!是 20922789888000 —— 全在uint64_t内;22!约 1.1e21,仍可存;23!≈ 2.58e22,uint64_t最大约 1.8e19,所以最大安全n是 20(20! = 2432902008176640000≈ 2.4e18)
避免把 1、0 或质数阶乘混进来
常见错误是没过滤质数,导致 is_composite_factorial(120) 返回 true(因为 5! = 120),但 5 不是合数。
另一个坑是边界值处理:
-
x == 1:对应0!和1!,但 0 和 1 都不是合数 → false -
x == 24:4! = 24,4 是合数 → true -
x == 720:6! = 720,6 是合数 → true -
x == 120:虽等于5!,但 5 是质数 → false -
x大于20!:直接返回 false,无需计算
别忘了用 std::sqrt 判断质数时,要处理 n == 4 这种小合数(sqrt(4)=2,2 能整除 4,正确);n == 9 同理。
C++ 实现示例(含溢出防护)
核心逻辑紧凑,不依赖大数库:
#include <cstdint>
#include <unordered_set>
#include <cmath><p>bool is_prime(uint64_t n) {
if (n </p>
<p>const std::unordered_set<uint64_t> COMPOSITE_FACTS = []{
std::unordered_set<uint64_t> s;
uint64_t fact = 1;
for (uint64_t n = 2; n 1 && fact <p>bool is_composite_factorial(uint64_t x) {
return COMPOSITE_FACTS.find(x) != COMPOSITE_FACTS.end();
}</p></uint64_t></uint64_t></p></cmath></unordered_set></cstdint>
注意:静态初始化捕获了所有合数阶乘(4!, 6!, 8!, 9!, 10!, 12!, ..., 20!),20! 是最后一个不溢出的;21 是合数,但 20! * 21 会溢出 uint64_t,所以停在 20 安全。
真正容易被忽略的是:合数不只有偶数——9、15、21 都是合数,但 21! 溢出,所以只到 20;而 9! = 362880 必须包含,否则漏判。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











