题目来自洛谷平台 (P1009 [NOIP1998 普及组] 阶乘之和)
题目
思路 通过题目可以大体看出这道题需要完成阶乘和求和两个算法,通过循环从1遍历到n,先算阶乘再求和
根据n的范围,我们知道n最大可以取到50,那么仅仅计算 n!就已经可以远超 long long 类型的储存范围了,此时需要考虑使用高精度加法和乘法
如果不会这两种算法可以去看之前写过的两篇算法讲解
高精度加法
高精度乘法
创建变量 首先创建两个数组用于保存每一步阶乘与求和的值
mul用于阶乘 add用于求和
为了方便操作,两个数组设置为全局变量;
1 int mul[110 ] = { 0 }, add[110 ] = { 0 };
主函数结构 为了使代码清晰明了,将阶乘和求和的功能封装为函数,这一步先写主函数的结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int main () { mul[100 ] = 1 ; add[100 ] = 1 ; int n; cin >> n; for (int i = 2 ; i <= n; i++) { Mul (i); Add (); } print (); return 0 ; }
阶乘函数
创建中间变量t,用于保存进位
数组中下标100处是数位的第一位,所以从100遍历到0
第一步,用当前数位的数乘以 x 再加上进位数
第二步,计算上一步结果的进位,用t保存进位数
第三步,模拟十进制,将当前数位的值更新为进位后的数
因为每一次计算阶乘都是连续的,例如:2! = 1 × 2 ,3! = 1 × 2 × 3,n! = (n-1)! × n
这个函数中 x 相当于上式的n,数组mul相当于(n-1)!,函数结束计算之后的数组mul相当于n!
因此不需要对每个数都完整的循环求阶乘,可以很大程度减少时间
1 2 3 4 5 6 7 8 9 10 void Mul (int x) { int t = 0 ; for (int i = 100 ; i >= 0 ; i--) { mul[i] = mul[i] * x + t; t = mul[i] / 10 ; mul[i] %= 10 ; } }
求和函数 (求和函数与阶乘函数的原理基本相同,都是按数位依次处理数值)
创建中间变量t,用于保存进位
数组中下标100处是数位的第一位,所以从100遍历到0
第一步,将上一个数阶乘的结果(数组mul)与数组add按数位相加,再加上进位数
第二步,计算当前数位的进位数,用t保存
第三步,模拟十进制,将当前数位的值更新为进位后的数
注:数组add保存的值是每次阶乘之后累加的结果
1 2 3 4 5 6 7 8 9 10 void Add () { int t = 0 ; for (int i = 100 ; i >= 0 ; i--) { add[i] = add[i] + mul[i] + t; t = add[i] / 10 ; add[i] %= 10 ; } }
打印函数 因为数字最低位在最右端,所以打印时需要从左端开始遍历
创建变量s用于保存结果最高位的下标
第一个for循环用来寻找结果的最高位,消除前导0,找到最高位时用s保存下标,跳出循环
第二个for循环用来遍历打印结果,从下标s处开始,到下标100处结束
初始化后的数组add中未被修改的元素一定为0,所以寻找最高位只需要从下标0开始遍历,如果add[i]处元素不为0那当前位置就是最高位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void print () { int s = 0 ; for (int i = 0 ; i <= 100 ; i++) { if (add[i] != 0 ) { s = i; break ; } } for (int i = s; i <= 100 ; i++) { printf ("%d" ,add[i]); } }
注意 如果构造函数写在主函数之后,不要忘记在主函数之前写函数头,否则函数无法使用
阶乘和求和函数中进位与更新数值的步骤顺序不能写反
完整代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 #include <iostream> using namespace std; int mul[110 ] = { 0 }, add[110 ] = { 0 }; void Mul (int x) { int t = 0 ; for (int i = 100 ; i >= 0 ; i--) { mul[i] = mul[i] * x + t; t = mul[i] / 10 ; mul[i] %= 10 ; } } void Add () { int t = 0 ; for (int i = 100 ; i >= 0 ; i--) { add[i] = add[i] + mul[i] + t; t = add[i] / 10 ; add[i] %= 10 ; } } void print () { int s = 0 ; for (int i = 0 ; i <= 100 ; i++) { if (add[i] != 0 ) { s = i; break ; } } for (int i = s; i <= 100 ; i++) { cout << add[i]; } } int main () { mul[100 ] = 1 ; add[100 ] = 1 ; int n; cin >> n; for (int i = 2 ; i <= n; i++) { Mul (i); Add (); } print (); return 0 ; }
如果文章内容有误,欢迎指出