题解:洛谷 AT_abc427_b Sum of Digits Sequence

【题目来源】

洛谷:AT_abc427_b [ABC427B] Sum of Digits Sequence - 洛谷

【题目描述】

对于一个正整数 \(x\),定义 \(f(x)\)\(x\) 的十进制表示各位数字之和。例如,\(f(123) = 1 + 2 + 3 = 6\)

定义一个无限序列 \(A = (A_0, A_1, A_2, \ldots)\),其定义如下:

  • \(A_0 = 1\)
  • 对于 \(i \geq 1\)\(A_i = \displaystyle\sum_{j = 0}^{i - 1} f(A_j)\)

给定一个正整数 \(N\),求 \(A_N\) 的值。

【输入】

输入从标准输入读取,格式如下:

\(N\)

【输出】

输出答案。

【输入样例】

6

【输出样例】

23

【核心思想】

  1. 问题分析:定义序列 \(A\) 满足 \(A_0 = 1\)\(A_i = \sum_{j=0}^{i-1} f(A_j)\)\(i \ge 1\)),其中 \(f(x)\)\(x\) 的各位数字之和。给定 \(N\),求 \(A_N\)。这是一个递推 + 数位拆分问题,关键在于理解递推关系并逐层计算,利用前缀和优化内层求和。

  2. 算法选择

    • 递推模拟:按定义从 \(A_0\) 递推至 \(A_N\),每个 \(A_i\) 依赖前面所有项
    • 前缀和优化:注意到 \(A_i = \sum_{j=0}^{i-1} f(A_j) = A_{i-1} + f(A_{i-1})\),可将 \(O(i)\) 的内层求和优化为 \(O(1)\)
    • 数位拆分:用 calc(x) 函数逐位取模累加,计算 \(f(x)\)
  3. 关键步骤

    • 初始化\(A_0 = 1\)\(f_0 = f(1) = 1\)
    • 递推计算\(i\)\(1\)\(N\)):
      • 利用前缀和性质:\(A_i = A_{i-1} + f(A_{i-1})\)
      • 计算 \(f_i = f(A_i)\)
    • 输出 \(A_N\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \cdot \log_{10} A_N)\),递推 \(N\) 步,每步数位拆分 \(O(\log_{10} A_i)\)
    • 空间复杂度:\(O(N)\),存储 \(A\)\(f\) 数组
  5. 递推与前缀和的核心思想

    • 递推关系转化\(A_i = \sum_{j=0}^{i-1} f(A_j) = \left(\sum_{j=0}^{i-2} f(A_j)\right) + f(A_{i-1}) = A_{i-1} + f(A_{i-1})\),将 \(O(i)\) 降为 \(O(1)\)
    • 数位拆分:通过不断 \(x \% 10\)\(x /= 10\) 提取各位数字,是计算数字和的标准方法
    • 适用于"递推定义序列 + 前缀和优化"类问题,核心是发现相邻项的递推关系

【算法标签】

入门 #递推

【代码详解】

#include <bits/stdc++.h>
using namespace std;

const int N = 105;  // 定义最大序列长度

int n;              // 序列长度
int a[N];           // 存储原始序列值
int f[N];           // 存储数字和序列值

/**
 * 计算一个整数的各位数字之和
 * @param x 输入整数
 * @return 各位数字之和
 */
int calc(int x)
{
    int res = 0;
    while (x)
    {
        res += x % 10;  // 取个位数并累加
        x /= 10;        // 去掉个位数
    }
    return res;
}

int main()
{
    // 输入序列长度
    cin >> n;

    // 初始化前两个元素
    a[0] = 1;  // 第0项为1
    a[1] = 1;  // 第1项为1
    f[0] = calc(a[0]);  // 计算第0项的数字和
    f[1] = calc(a[1]);  // 计算第1项的数字和

    // 计算序列的后续元素
    for (int i = 2; i <= n; i++)
    {
        // 计算a[i]:前i项f值的和
        for (int j = 0; j < i; j++)
        {
            a[i] += f[j];
        }

        // 计算f[i]:a[i]的各位数字之和
        f[i] = calc(a[i]);
    }

    // 输出第n项的值
    cout << a[n] << endl;

    return 0;
}

【运行结果】

6
23
posted @ 2026-08-27 11:03  团爸讲算法  阅读(10)  评论(0)    收藏  举报