洛谷 P1009 [NOIP1998 普及组] 阶乘之和

[NOIP1998 普及组] 阶乘之和

题目描述

用高精度计算出 S = 1 ! + 2 ! + 3 ! + ⋯ + n ! S = 1! + 2! + 3! + \cdots + n! S=1!+2!+3!++n! n ≤ 50 n \le 50 n50)。

其中 ! 表示阶乘,定义为 n ! = n × ( n − 1 ) × ( n − 2 ) × ⋯ × 1 n!=n\times (n-1)\times (n-2)\times \cdots \times 1 n!=n×(n1)×(n2)××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 1n50

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];
	} 

	
} 
  • 17
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诗九趁年华

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值