三角数是能排成等边三角形的点数,第n个为t(n)=n(n+1)/2;判断x是否为三角数,只需验证1+8x是否为完全平方数且其平方根为奇数。

什么是三角数?先看数学本质
三角数是能排成等边三角形的点数,第 n 个三角数为 T(n) = n<em>(n+1)/2</em>。所以判断一个正整数 x 是否为三角数,等价于:是否存在正整数 n,使得 n(n+1)/2 == x。
直接遍历 n 从 1 到 sqrt(2*x) 虽然可行,但不是“极速”解法——真正快的是用求根公式反推。
用二次方程判别式一步判定
把 n<em>(n+1)/2 == x</em> 整理为:n² + n - 2x == 0。
解这个方程,正根为:n = (-1 + sqrt(1 + 8x)) / 2。
所以只需验证两件事:
-
1 + 8*x是完全平方数(即开方后为整数) - 开方结果
sqrt(1 + 8*x)是奇数(因为-1 + 奇数才能被 2 整除)
实际代码中,推荐这样写:
bool isTriangular(long long x) {
if (x <p>注意:<code>sqrt</code> 返回 <code>double</code>,直接转 <code>long long</code> 会截断,必须先四舍五入或用 <code>llround</code>,更稳妥是:</p><pre class="brush:php;toolbar:false;">long long root = static_cast<long long>(std::sqrt(disc) + 0.5);</long>整数开方防精度坑:为什么 sqrt 容易误判
对大整数(比如 x > 1e12),double 只有约 15–17 位有效数字,sqrt(1 + 8*x) 可能刚好卡在两个整数之间,导致 static_cast<long long>(sqrt(...))</long> 向下取整出错。
例如:x = 180625 → disc = 1445001,真实根是 1202.08…?不,其实是 1202 精确值 —— 但 double 表示可能变成 1201.999999999,截断后得 1201,误判。
解决方案:
- 用
llround(sqrt(disc))替代强制转换 - 或手写整数二分开方(对
disc在[0, 8e18]范围内也很快) - 更简单:算出
root后,检查root<em>root</em>、(root-1)(root-1)、(root+1)*(root+1)是否等于disc
边界与类型溢出必须手动防护
8<em>x</em> 很容易溢出:int 最大值约 2e9,8x 就超了;unsigned int 也不够。务必用 long long 或 uint64_t。
常见错误写法:
int x = ...; long long disc = 1 + 8 * x; // 先按 int 算,再转 long long → 已溢出!
正确写法:
long long x = ...; long long disc = 1LL + 8LL * x;
或者强制字面量带后缀:1LL、8LL。
另外,x=0 和 x=1 要单独考虑:1 是第 1 个三角数,0 不是正整数,按题意应排除。
最易被忽略的点:浮点开方精度 + 整数溢出 + 截断方式,三者叠加会让看似简单的公式在大数下静默失效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











