洛谷[模拟与高精度]-P1009 [NOIP1998 普及组] 阶乘之和
题目描述
用高精度计算出 S=1!+2!+3!+⋯+n!
其中“!”表示阶乘,例如:5!=5×4×3×2×1
输入格式
一个正整数 n。
输出格式
一个正整数 S,表示计算结果。
输入输出样例
输入 #1
3
输出 #1
9
说明/提示
【数据范围】
对于 100% 的数据,1≤n≤50。
【其他说明】
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n≤20,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
思路
这道题就是写两个高精运算:高精乘,高精加。
最关键在这个循环怎么写,我定义了两个数组,a和ans。
a存储每一个阶乘项,依次存储1!, 2!, 3!, 4!, … , n!;
ans存储阶乘之和,依次存储1!,1! + 2!, 1! + 2! + 3!, … , 1! + 2! + 3! + … + n!。
每一次循环中,在“上一个阶乘项”的基础上高精乘一个数字算出本次的阶乘项,然后再用算出的结果高精加“上一个阶乘之和”。循环结束之后,ans数组存储的就是所求答案的倒序。
另外幸运的是,这里的高精乘写起来比较简单,因为其中一个乘数最大只有50,只需将另一个乘数数组存储即可(补充:通过之后的学习我知道了其实这里叫高精乘低精)。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[1005]; //存储各个阶乘项
int ans[1005]; //存储阶乘项之和
void mcl(int i) { //高精乘
int jw = 0;
for (int j = 1; j <= 1000; j++) {
a[j] = a[j] * i + jw;
jw = a[j] / 10; //进位
a[j] = a[j] % 10; //本位
}
}
void add() { //高精加
int jw = 0;
for (int j = 1; j <= 1000; j++) {
ans[j] = ans[j] + a[j] + jw;
jw = ans[j] / 10; //进位
ans[j] = ans[j] % 10; //本位
}
}
int main()
{
//输入
cin>>n;
//高精运算
a[1] = 1;
for (int i = 1; i <= n; i++) {
mcl(i); //高精乘
add(); //高精加
}
//输出
int flag = 0;
for (int i = 1000; i >= 1; i--) {
if (ans[i] != 0) { //找到第一个不为0的最高位
flag = i;
break;
}
}
for (int i = flag; i >= 1; i--) {
cout<<ans[i];
}
return 0;
}