题目链接
题目描述
对于一个数,把它所有位上的数字进行加和,得到新的数。重复执行若干次,直到结果是个位数为止。输出最终的这个个位数。
解题思路
本题要求计算一个整数的“数根”(Digital Root)。这个问题既可以通过直接模拟,也可以通过一个巧妙的数学性质在常数时间内解决。
-
模拟法
最直观的方法是按照题目描述进行模拟:
- 当给定的数字
大于等于
时,我们进入一个循环。
- 在循环内部,我们计算
的各位数字之和,并用这个和来更新
。
- 重复这个过程,直到
变成一个小于
的个位数。
这个方法是完全可行的,但对于位数非常多的数字,可能需要多次循环。
- 当给定的数字
-
数论法(模 9 性质)
一个更高效、更优雅的方法是利用数论中的一个著名性质:一个非负整数模
的余数与其各位数字之和模
的余数是相同的。
数学上,对于任意非负整数
,设
是其各位数字之和,则有:
由于题目要求反复执行这个过程,这意味着最终得到的那个个位数(即数根)与原始数字
在模
的意义下是同余的。
由此我们可以推导出结论:
- 如果
,其数根就是
。
- 如果
且是
的倍数(即
),它的数根是
。
- 如果
且不是
的倍数,那么它的数根就是
。
这三种情况可以被一个统一的公式所表达: 对于任意非负整数
,其数根为
。
这个公式直接给出了答案,无需循环,时间复杂度为
。
- 如果
代码
#include <iostream>
using namespace std;
int main() {
// 读取初始数字
long long N;
cin >> N;
// 根据数论公式直接计算并输出结果
if (N == 0) {
cout << 0 << endl;
} else {
cout << (N - 1) % 9 + 1 << endl;
}
return 0;
}
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
// 读取初始数字
long N = sc.nextLong();
// 根据数论公式直接计算并输出结果
if (N == 0) {
System.out.println(0);
} else {
System.out.println((N - 1) % 9 + 1);
}
}
}
def main():
# 读取初始数字
N = int(input())
# 根据数论公式直接计算并输出结果
if N == 0:
print(0)
else:
print((N - 1) % 9 + 1)
if __name__ == "__main__":
main()
算法及复杂度
-
算法:数论(数根、模运算)
-
时间复杂度:
。我们使用了一个数学公式直接计算结果,其时间消耗与输入数字
的大小无关。
-
空间复杂度:
。算法只需要常数空间来存储变量。