必须用数学公式法,因暴力循环对1e12超时;需用long long防溢出(如8ll*n),判别式1+8n须整数校验平方根,且还原k必须为正整数。

能,而且必须用数学公式法——暴力循环对 1e12 量级输入会超时,而公式法是 O(1) 的,但浮点精度陷阱不处理好,结果一定错。
判别式 1 + 8 * n 必须用 long long 计算
哪怕输入是 int,8 * n 在 n > 2.7e8 时就可能溢出 int;n = INT_MAX(约 2.1e9)时,1 + 8 * n ≈ 1.7e10,已超出 int 范围。不加 LL 后缀或不转 long long,直接得到错误的判别式值。
- 写成
long long disc = 1 + 8LL * n,不是8 * n + 1 - 若
n是unsigned long long,则必须用8ULL防止乘法在unsigned long上截断 - 判别式为负数的情况不会发生(
n > 0保证disc > 0),但函数开头仍需检查n 直接返回 <code>false
std::sqrt 返回值必须校验,不能直接取整
double 对大于 2^53(约 9e15)的整数无法精确表示,std::sqrt(disc) 可能返回略小或略大的值。比如 disc = 8000000001(对应 n = 1000000000),真实平方根是 89442.72...,static_cast<long long>(std::sqrt(disc))</long> 可能得 89442,而 89442 * 89442 != disc,误判为非三角形数。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
- 正确做法:先算
long long s = static_cast<long long>(std::sqrt(static_cast<double>(disc)) + 0.5)</double></long>,再检查s * s == disc - 更稳妥:在
s-1、s、s+1三个值里穷举验证,因为真实整数根只可能落在这个范围内 - 不要用
std::round或llround—— 它们依赖double精度,而大数下double已失真
平方根验证通过后,还要检查奇偶性和正整数性
判别式是完全平方数只是必要条件,不是充分条件。disc 是完全平方数,仅说明方程有有理根;但要保证 k = (sqrt(disc) - 1) / 2 是正整数,还需两步:
-
sqrt(disc)必须是奇数:否则sqrt(disc) - 1是偶数,除以 2 才可能得整数;可写成(s - 1) % 2 == 0 -
(s - 1) / 2必须 > 0:即s > 1,排除n = 0或负数输入漏检的情况 - 例如
n = 1→disc = 9→s = 3→(3 - 1) / 2 = 1,合法;n = 2→disc = 17→ 不是完全平方数,直接拒绝
真正容易被忽略的是:三步缺一不可——判别式计算防溢出、平方根用整数校验、还原后的 k 必须为正整数。少做任何一步,在边界值(如 n = 1、n = 1000000000、n = LLONG_MAX / 8)上都会出错。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










