题目描述:
用高精度计算出S=1!+2!+3!+…+N!(N≤50),其中"!"表示阶乘,例如:5!=5*4*3*2*1。
输入正整数N,输出计算结果S。
输入格式
一个正整数 n。
输出格式
一个正整数 S,表示计算结果。
解题思路:
-----由于阶乘的增长速度特别快,计算结果S的最大值可以达到70多位数,远超我们计算机能够表达的范围,所以我们不能用常规的变量记录阶乘以及阶乘和的结果。那我们要用什么方式记录计算结果呢?
-----我们设置两个大小为MAX_SIZE的整形数组fact,res分别记录阶乘以及阶乘和的结果,数组中的每一个元素就代表了一位数(0~9),只要调整MAX_SIZE的大小,就可以解决MAX_SIZE以内精度的计算。计算过程怎么实现呢?
-----由于在相乘或相加的运算过程中会发生溢出(产生进位),超过了一个数组元素能表示的范围,这时我们用整型变量c来表示进位,当运算过程产生了进位,我们就用c记录这个进位的结果,运用到下一位数运算的过程。
这里的进位c可以是多位数,我们以较为复杂的乘法作为例子:
456 x 7:
第一次运算:个位数6和7相乘,得到42,即进位为4,个位数运算后结果为2
第二次运算:十位数5和7相乘,结果39(乘法结果35加前一位数进位4),得到进位3和十位数结果9
第三次运算:百位数4和7相乘,得到结果31,进位为3,百位数结果为1
第四次运算:运算已经结束了,只需要把前一位结果放到千位数就行,如果是两位数进位,则分别放到万位和千位。
补充一点:我们用len1,len2分别表示fact,res的位数大小,因为计算之前我们并不知道计算结果会有多少位数,所以MAX_SIZE可能会设置非常大 ,这会让很多计算结果产生特别多的无效位(前导0),所以记录数组有效位长度是非常有必要的。
而len1和len2的更新方式为:(计算后的长度)=(计算前的长度)+(最后一位进位的位数)
大家可以跳回第三步运算自行理解。
加法的运算过程和乘法类似,较为简单就不演示了。
#include<iostream>
using namespace std;
const int MAX_SIZE = 1000; //数字位数
//相乘函数
int multi(int* fact, int i, int len)
{
int c = 0; //进位
//如果没定义len,则for的判断语句(k < MAX_SIZE)
for (int k = 0; k < len; k++)
{
int mul = fact[k] * i + c; //位数相乘结果,并加上前一位数的进位
fact[k] = mul % 10; //更新当前位数
c = mul / 10; //更新进位
}
//最后一位相乘的结果可能有进位,我们要把进位更新到fact中,并且更新长度
while (c)
{
fact[len++] = c % 10;
c /= 10;
}
return len;
//如果函数参数len是用引用传递的话,这里不用返回也可以更新len的值
//详见(函数参数传递,值传递、引用传递和地址传递的区别)
}
//加法函数
int add(int* fact, int* res, int len)
{
//len表示 fact 和 res,两个数组中的位数较大值
int c = 0; //进位
for (int k = 0; k < len; k++)
{
int sum = fact[k] + res[k] + c; //位数相加,并加上前一位数的进位
res[k] = sum % 10; //更新当前位数
c = sum / 10; //更新进位
}
//最后一位相加的结果可能有进位,我们要把进位更新到res中,并且更新长度
while (c)
{
res[len++] = c % 10;
c /= 10;
}
return len;
}
int main()
{
int n; cin >> n;
//定义两个数组,分别表示阶乘,阶乘和
int fact[MAX_SIZE], res[MAX_SIZE];
//初始化两个数组
for (int i = 0; i < MAX_SIZE; i++)
{
fact[i] = 0;
res[i] = 0;
}
fact[0] = 1;
int fact_len = 1, res_len = 0; //两个数组的位数
for (int i = 1; i <= n; i++)
{
fact_len = multi(fact, i, fact_len);//计算i的阶乘,并返回阶乘结果fact长度
res_len = add(fact, res, fact_len); //计算i的阶乘和,并返回相加结果res长度
//add的函数第三个参数表示有效位数,所以传入两个数组长度的较大值
// fact_len的有效位一般比res_len大,所以传入fact_len
//如果不知道fact_len和res_len那个大,可以用下面代码解决
/*
int temp_len = max(fact_len, res_len);
res_len = add(fact, res, temp_len);
*/
}
//输出(从高位开始输出)
for (int i = res_len - 1; i >= 0; i--)
{
cout << res[i];
}
cout << endl;
}
如果觉得本文有帮助到您,请点击下方一键三连,助力一下博主!