B4344 [语言月赛 202506] 数字转转转 题解

· · 题解

Source & Knowledge

2025 年 6 月语言月赛,由洛谷网校入门计划/基础计划提供。

题目大意

给定一个正整数 x,定义一次“数字转转转”操作为将其每一位数字相加得到一个新数。例如,375 经过一次操作变为 3 + 7 + 5 = 15,再次操作变为 1 + 5 = 6。现在,对于 1n 的每个数字 i,需要对其进行 a_i 次“数字转转转”操作,并输出最终的结果。

题目分析

对于每个数字 i(从 1n),我们将其作为初始值 x。然后,循环 a_i 次。在一个内部循环中,计算 x 的各位数字之和,并将结果赋值回 x

计算各位数字之和的方法:

int sum = 0;
while (num > 0) {
   sum += num % 10; // 取出个位数字
   num /= 10;       // 去掉个位数字
}
return sum;

将这个逻辑应用到题目中:

// 对于从1到n的每个数字i
for (int i = 1; i <= n; ++i) {
    int cnt; // 当前数字i需要进行的转转转次数
    cin >> cnt;

    int x = i; // 初始值为i
    // 进行转转转操作,最多cnt次,但只要x变为个位数就停止
    for (int j = 1; j <= cnt; ++j) {
        int sum = 0;
        // 计算x的各位数字之和
        while (x > 0) {
            sum += x % 10;
            x /= 10;
        }
        x = sum; // 更新x为各位数字之和
        if (x < 10) {    // 如果x已经是小于10的个位数,则后续操作结果不变
            break;       // 跳出内层循环
        }
    }
    cout << x << " "; // 输出最终结果
}

代码中有一个 if (x < 10) { break; },现对其作一个直观解释。

由于“数字转转转”操作的最终结果是一个个位数,并且一旦达到个位数,后续操作结果不变,这意味着我们不需要真正执行 a_i 次操作。实际上,对于任何大于 9 的数,经过两三次操作通常就会变成小于 10 的数。例如 99999 \to 9+9+9+9+9 = 45 \to 4+5 = 9。即使 a_i 非常大(例如 10^9),我们也不需要循环 10^9 次。我们只需要循环直到当前数字变为个位数即可。一旦变为个位数,就可以直接跳出循环,输出结果。

题目中的 a_i 实际上只影响循环的上限,真正决定循环次数的是 x < 10 的条件,次数可能远远达不到 a_i。因为一旦 x 变为个位数,它就不会再改变,所以即使 a_i 很大,我们也不需要执行那么多次操作,很少次数(两三次)的操作即可。这正是代码中的 if (x < 10) break; 的作用。