Skip to content

喵哈喽~ 主人,今天我们来解决一个超级可爱的问题,关于三角数的判断哦!让本喵来带你一步一步地分析和解决它吧!

题目大意

这个问题呀,是想让我们判断一个给定的整数 n 是不是一个“三角数” (Triangular number) 呢。

那什么是三角数呀?喵~ 想象一下我们有很多小点心,把它们排列成一个等边三角形。

  • n=1 时,1个点心自己就能成一个最小的三角形,所以 1 是三角数。
  • n=2 时,我们用 3 个点心可以摆成一个边上有 2 个点心的三角形,所以 3 是三角数。
  • n=3 时,需要 6 个点心才能摆成边上有 3 个点心的三角形,所以 6 是三角数。

规律就是,第 k 个三角数是 1 + 2 + 3 + ... + k 的和。

我们的任务就是,输入一个数字 n (1 ≤ n ≤ 500),然后回答 “YES” 或者 “NO”,告诉提问者它是不是三角数。

题解方法

要怎么判断 n 是不是三角数呢?喵呜~ 方法其实很直接啦!

我们可以从小到大,一个一个地把三角数算出来,然后看看 n 是不是我们算出来的其中一个。

  1. 我们先算第 1 个三角数:1
  2. 再算第 2 个三角数:1 + 2 = 3
  3. 再算第 3 个三角数:1 + 2 + 3 = 6
  4. ...以此类推...

我们可以用一个循环来做这件事。在循环里,我们维护一个变量 sum,它表示当前正在计算的三角数。

  • k=1 开始,每次循环都把 k 加到 sum 上。
  • 每次更新 sum 之后,我们就检查一下:
    • 如果 sum 正好等于 n,那太棒啦!说明 n 就是一个三角数,我们就可以自信地输出 YES,然后结束程序啦。
    • 如果 sum 不小心超过了 n,因为三角数是越来越大的,所以后面的三角数肯定也比 n 大。这说明 n 不可能是三角数了,我们就可以输出 NO,然后也结束程序。

这个方法就像我在搭积木一样,一块一块往上加,看看能不能正好搭到 n 那么高。如果正好搭到,就成功了!如果不小心搭得更高了,那就失败了喵~ 因为 n 最大也只有 500,所以这个过程很快就会结束的,完全不用担心会超时哦!

题解

好啦,现在让我们来看看具体的代码是怎么实现的吧,喵~

cpp
#include <iostream>

// 这个程序用来判断一个给定的整数是不是三角数。
// 三角数是前 k 个正整数的和,T_k = 1 + 2 + ... + k = k * (k + 1) / 2。
//
// 我们的方法是按顺序生成三角数,然后检查给定的数字 n 是否是其中之一。
// 我们从 k=1 开始,计算 T_1 = 1。
// 然后 k=2, T_2 = 1 + 2 = 3。
// 然后 k=3, T_3 = 3 + 3 = 6,以此类推。
//
// 我们可以用一个循环来维护一个累加和。
// 在每次迭代 k 中,我们将 k 加到 sum 上。
// - 如果 sum 等于 n,那么 n 就是一个三角数。
// - 如果 sum 超过 n,那么我们就已经错过了 n,它不可能是三角数,
//   因为三角数序列是严格递增的。
//
// 题目限制 n <= 500。不超过 500 的最大三角数是 T_31 = 496。
// 下一个是 T_32 = 528。所以循环最多运行 32 次,非常高效。

int main() {
    // 这两行是为了在竞赛中让输入输出更快,是好习惯哦!
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n;
    // 读取主人输入的数字 n
    std::cin >> n;

    int sum = 0;
    // 这是一个无限循环,但别担心,我们会在内部找到答案后跳出!
    for (int k = 1; ; ++k) {
        // 累加 k,生成下一个三角数
        sum += k;

        // 检查 sum 是否等于 n
        if (sum == n) {
            // 找到了!n 是三角数,输出 YES
            std::cout << "YES\n";
            // 任务完成,可以回家啦~
            return 0;
        }

        // 检查 sum 是否已经超过了 n
        if (sum > n) {
            // 哎呀,超过了。n 不可能是三角数,输出 NO
            std::cout << "NO\n";
            // 同样结束程序
            return 0;
        }
    }

    // 因为上面的循环总会找到答案并退出,所以程序永远不会运行到这里。
    return 0;
}

代码讲解:

  1. int n; std::cin >> n;: 定义一个整数变量 n,然后把主人你输入的数字存进去。
  2. int sum = 0;: 这是我们的累加器,用来计算当前的三角数,一开始是 0。
  3. for (int k = 1; ; ++k): 这是一个 for 循环,k 从 1 开始,每次循环增加 1。它没有写结束条件,因为我们会在循环内部通过 return 0; 来结束整个程序。
  4. sum += k;: 在每一轮循环中,把当前的 k 加到 sum 上。sum 的变化过程就是 1, 1+2=3, 3+3=6, 6+4=10 ... 这正是三角数的序列!
  5. if (sum == n): 判断我们刚刚算出来的三角数 sum 是不是正好等于 n。如果是,就说明 n 是一个三角数,输出 YES 并结束。
  6. if (sum > n): 如果 sum 不等于 n,我们再判断它是不是已经大于 n 了。如果是,说明我们已经“错过”了 n,它不可能是三角数了,所以输出 NO 并结束。

这个逻辑非常清晰,对不对呀?嘻嘻~

知识点介绍

关于三角数 (Triangular Number),还有一些更有趣的知识呢,主人要听吗?喵~

1. 三角数的通项公式

其实呀,我们不需要每次都从 1 开始累加来计算第 k 个三角数。它有一个非常漂亮的数学公式!

k 个三角数 TkT_k 等于:

Tk=k(k+1)2 T_k = \frac{k(k+1)}{2}

这个公式其实就是等差数列求和公式啦!首项是 1,末项是 k,项数是 k,所以和是 (首项 + 末项) * 项数 / 2,也就是 (1 + k) * k / 2

2. 一种更数学的解法

利用上面的公式,我们可以想出另一种解法哦!

如果一个数 n 是三角数,那么一定存在一个正整数 k,使得:

k(k+1)2=n \frac{k(k+1)}{2} = n

我们来把这个方程变一下形:

k(k+1)=2n k(k+1) = 2n

k2+k2n=0 k^2 + k - 2n = 0

这是一个关于 k 的一元二次方程!我们可以用求根公式来解出 k。但还有个更巧妙的方法:

我们把方程 k^2 + k - 2n = 0 两边都乘以 4,再做一些变换:

4k2+4k8n=0 4k^2 + 4k - 8n = 0

(4k2+4k+1)18n=0 (4k^2 + 4k + 1) - 1 - 8n = 0

(2k+1)2=8n+1 (2k + 1)^2 = 8n + 1

看到没!如果 n 是一个三角数,那么 8n + 1 就必须是一个完全平方数!而且它必须是一个奇数的平方(因为 2k+1 是奇数)。

所以,判断 n 是否为三角数的另一种方法是:

  1. 计算 m = 8 * n + 1
  2. 判断 m 是否为一个完全平方数。
  3. 如果 m 是完全平方数,再判断它的平方根是不是一个奇数。

如果都满足,那么 n 就是一个三角数。是不是很神奇呀?不过对于这道题来说,直接循环模拟的方法已经足够简单和高效啦!

好啦,今天的讲解就到这里啦!希望主人能够喜欢,喵~ 如果还有其他问题,随时可以再来找我哦!

Released under the MIT License.