题目跳转:P1009 [NOIP1998 普及组] 阶乘之和
思路
本题主要考察高精度加法与高精度乘法。
高精度是什么
在科学计算中,我们往往要计算一个几百亿大或者需要精确到小数点后几百位的数。这些数字远远超过了程序语言自带的数据类型,此时我们需要一种不同的记录数据的方式,即用字符串记录数据。
比如,我们用字符串记录1234这个数字时,我们会构造一个char 数组 listA,然后令listA [0] = ‘4’,listA [1] = ‘3’,listA [2] = ‘2’,listA [3] = ‘1’,此时我们是按反方向存储了1234,至于为何,接下来会说明,接着我们用相同方式,用listB存储9876。
高精度加法
首先我们回顾一下我们平时列竖式计算加法的过程。我们的基本思想是按位计算,结果的每一位是两者相应位数相加再加上上一位的进位。
比如我们来算一下上面的例子,我们用char数组result来存储结果,用int r 记录进位,用int temp_sum记录每一位相加和。首先我们计算listA[0]+listB[0],即temp_sum = listA[0]-‘0’ + listB[0] - ‘0’;然后计算余数,r = temp_sum /10;计算存入result中的数,temp_sum = temp_sum % 10,result.push(temp+‘0’)。如此循环
在此过程中,我们需要注意几种情况,一种是在计算结束后还有余数(突破最高位),我们需要将余数也按十进制放入result。另一种是在加法过程中,出现了一个加数先加完的情况,如2位数加4位数,因此我们在temp_sum计算时,需要进行判断
下面给出代码演示
// 高精度加法
vector<char> sum(vector<char> temp, vector<char> ans)
{
int len1 = temp.size();
int len2 = ans.size();
int len = max(len1, len2); // 取最大长度
int temp_sum = 0; // 每位数的和
int r = 0; // 进位
vector<char> res; // 结果
for (int i = 0; i < len; i++)
{
// 每位数的和
if (i < len1) // temp里面还有数
temp_sum += temp[i] - '0';
if (i < len2) // ans里面还有数
temp_sum += ans[i] - '0';
temp_sum += r; // 加上进位
r = temp_sum / 10; // 更新进位
res.push_back(temp_sum % 10 + '0');
temp_sum = 0; // 重置为0用于下一个循环
}
if (r != 0) // 如果有进位
{
res.push_back(r + '0');
}
return res;
}
高精度数与int乘法
在这道题中,我们的阶乘可以从上一个阶乘结果基础上乘一个int类型数得到,主要思想与加法类似,就是高精度的每位乘上乘数加上上一位的进位,得到result对应位数上的数字
下面给出代码演示
// 高精度乘法
vector<char> multiply(vector<char> temp, int n)
{
int len = temp.size();
int temp_sum = 0;
int r = 0;
vector<char> res;
for (int i = 0; i < len; i++)
{
temp_sum = (temp[i] - '0') * n + r;
r = temp_sum / 10;
res.push_back(temp_sum % 10 + '0');
}
while (r != 0) // 如果有进位
{
res.push_back(r % 10 + '0');
r /= 10;
}
return res;
}
AC代码
#include<iostream>
#include<vector>
using namespace std;
// 高精度加法
vector<char> sum(vector<char> temp, vector<char> ans)
{
int len1 = temp.size();
int len2 = ans.size();
int len = max(len1, len2); // 取最大长度
int temp_sum = 0; // 每位数的和
int r = 0; // 进位
vector<char> res; // 结果
for (int i = 0; i < len; i++)
{
// 每位数的和
if (i < len1) // temp里面还有数
temp_sum += temp[i] - '0';
if (i < len2) // ans里面还有数
temp_sum += ans[i] - '0';
temp_sum += r; // 加上进位
r = temp_sum / 10; // 更新进位
res.push_back(temp_sum % 10 + '0');
temp_sum = 0; // 重置为0用于下一个循环
}
if (r != 0) // 如果有进位
{
res.push_back(r + '0');
}
return res;
}
// 高精度乘法
vector<char> multiply(vector<char> temp, int n)
{
int len = temp.size();
int temp_sum = 0;
int r = 0;
vector<char> res;
for (int i = 0; i < len; i++)
{
temp_sum = (temp[i] - '0') * n + r;
r = temp_sum / 10;
res.push_back(temp_sum % 10 + '0');
}
while (r != 0) // 如果有进位
{
res.push_back(r % 10 + '0');
r /= 10;
}
return res;
}
int main()
{
int n;
cin >> n;
vector<char> temp = {'1'}; // 阶乘初始值为1
vector<char> ans = {'0'}; // 累加和初始为0
for (int i = 1; i <= n; i++)
{
temp = multiply(temp, i);
ans = sum(temp, ans);
}
// 输出结果,倒序输出
for (int i = ans.size() - 1; i >= 0; i--)
{
cout << ans[i];
}
return 0;
}