[NOIP1998 普及组] 阶乘之和
题目描述
用高精度计算出 S = 1 ! + 2 ! + 3 ! + ⋯ + n ! S = 1! + 2! + 3! + \cdots + n! S=1!+2!+3!+⋯+n!( n ≤ 50 n \le 50 n≤50)。
其中 !
表示阶乘,定义为
n
!
=
n
×
(
n
−
1
)
×
(
n
−
2
)
×
⋯
×
1
n!=n\times (n-1)\times (n-2)\times \cdots \times 1
n!=n×(n−1)×(n−2)×⋯×1。例如,
5
!
=
5
×
4
×
3
×
2
×
1
=
120
5! = 5 \times 4 \times 3 \times 2 \times 1=120
5!=5×4×3×2×1=120。
输入格式
一个正整数 n n n。
输出格式
一个正整数 S S S,表示计算结果。
样例 #1
样例输入 #1
3
样例输出 #1
9
提示
【数据范围】
对于 100 % 100 \% 100% 的数据, 1 ≤ n ≤ 50 1 \le n \le 50 1≤n≤50。
NOIP1998 普及组 第二题
解题
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int lens=0, lenns=0;
int s[201];
int ns[201];
int c[201];
// 高精度乘法 ,计算 s * b
void multi_s(int b) {
memset(c, 0, sizeof(c)); // 重置临时计算结果数组
// 把整型b转为数组,并记录长度,因为阶乘最大数字是 50,整型足够。
// 临时数组tempb使用3个长度足够。
int tempb[3] = {0,0,0};
int lenb=0;
while (b > 0) {
lenb++;
tempb[lenb] = b % 10;
b /= 10;
}
// 乘法运算
int x = 0,xx;
for (int si = 1; si <= lens; si++) {
x=0;// 重置进位值为0
for (int bi = 1; bi <= lenb; bi++) {
// (si+bi-1)位置上原本的数 + 两个位置的数的积 + 前一位计算进位的数x
c[si+bi-1] = c[si+bi-1] + s[si]*tempb[bi] + x;
x = c[si+bi-1] / 10; // 获取进位数
c[si+bi-1] %= 10;// 获取当前位数
}
// 注意一轮计算过后有进位的情况。x还有剩余值,需要再进位。
c[si+lenb]=x;
}
lens = lens+lenb; // 修改积的数组长度。
while(c[lens] == 0) {
lens--; // 去除最高位上多余的0
}
// c数组的值复制给s数组,用于后续加法计算和阶乘计算
for (int i = 1; i<=lens; i++) {
s[i] = c[i];
}
}
// 高精度加法函数,计算 ns + s
void add_ns() {
memset(c, 0, sizeof(c)); // 重置临时数组c
int i=0,x=0;
while(i<lenns || i < lens) { // 遍历两个数组的所有数字
i++;
c[i] = ns[i] + s[i] + x;// 相同位置数字相加 + 前一位进位数x
x = c[i] / 10; // 求进位
c[i] = c[i] % 10;// 当前位数字
}
if (x > 0) {
c[++i] = x; // 如果x有剩余,则需要再进一位
}
lenns = i; // 修改数组长度
// 复制数组给ns
for (int j=1; j<=lenns; j++) {
ns[j] = c[j];
}
}
int main() {
int n;
cin >> n;
s[1] = 1;
lens = 1;
for (int i=1; i<=n; i++) {
multi_s(i);
add_ns();
}
// 倒序打印ns数组(从高位到地位)
for (int i=lenns; i >0; i--) {
cout << ns[i];
}
}