P1009 [NOIP1998 普及组] 阶乘之和

文章讲述了如何使用C++编程解决计算1到n的阶乘和的问题,从基础的循环计算方法,到优化后的代码实现,再到使用高精度计算进行求解,逐步展示了计算阶乘和的不同策略。对于较大的n值,常规类型可能会溢出,因此需要采用高精度计算来保证结果的准确性。
摘要由CSDN通过智能技术生成

题目描述

用高精度计算出 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,表示计算结果。

样例输入

3

样例输出

9

提示

【数据范围】

对于 100 % 100 \% 100% 的数据, 1 ≤ n ≤ 50 1 \le n \le 50 1n50

1、刚学习循环时,写出下方的代码就很好
此代码适合的数据范围 1 ≤ n ≤ 20 1 \le n \le 20 1n20
通过计算器计算发现,20的阶乘大约是2.4x1018 ,而1 ~ 19的阶乘和是小于20的阶乘的,因此1 ~ 20 的阶乘和小于两倍的20的阶乘,即4.8x1018 。用long long可以存下。提交代码可以得50分。

1.1、一般代码


#include<iostream>
using namespace std;
int main() {
	int n;
	cin >> n;
	//s用于累计阶乘的和,x用于存储i的阶乘
	long long s = 0, x = 1;
	for (int i = 1; i <= n; i++) {
		//计算i的阶乘
		x = 1; //将x重置为1
		for (int j = 1; j <= i; j++)
			x *= j;
		//累加阶乘的和
		s += x;
	}
	cout << s;
	return 0;
}

1.2、优化后的代码


//优化规则:n的阶乘等于(n-1)的阶乘*n,所以不用每次都重新从1开始乘到i,来计算i的阶乘
#include<iostream>
using namespace std;
int main() {
	int n;
	cin >> n;
	//s用于累计阶乘的和,x用于存储i的阶乘
	long long s = 0, x = 1;
	for (int i = 1; i <= n; i++) {
		//计算i的阶乘
		x *= i; //n的阶乘等于(n-1)的阶乘*n
		//累加阶乘的和
		s += x;
	}
	cout << s;
	return 0;
}

2、高精度计算代码

//满分代码,学了高精度计算之后再来研究
#include<iostream>
#include<cstring>
using namespace std;
//a数组用于乘法运算,初值是1;sum数组用于阶乘的累加,初值是0
//a[0]中保存a中数字的位数,s[0]中保存s中数字的位数
int a[500],sum[500];
void mul(int x)//高精乘
{
	for(int i=1;i<=a[0];i++)
		a[i]*=x;
	for(int i=1;i<=a[0];i++)
	{
		a[i+1]+=a[i]/10;
		a[i]%=10;
	}
	//找到最高位
	int t=a[0];
	while(a[t+1]>0)
		t++;
	//处理进位
	while(a[t]>10)
	{
		a[t+1]+=a[t]/10;
		a[t]%=10;
		t++;
	}
	a[0]=t; //记录数字的位数
}
void add()//高精加
{
	if(sum[0]<a[0])
		sum[0]=a[0];
	for(int i=1;i<=sum[0];i++)
	{
		sum[i]+=a[i];
		sum[i+1]+=sum[i]/10;
		sum[i]%=10;
	}
	//计算数字的位数
	if(sum[sum[0]+1]>0)
		sum[0]+=1;
}
int main()
{
	int n;
	cin>>n;
	
	a[0]=1;a[1]=1;sum[0]=1;sum[1]=0;
	for(int i=1;i<=n;i++)
	{
		mul(i);//计算i的阶乘
		add();//累计阶乘和
	}
	//输出结果
	for(int i=sum[0];i>=1;i--)
		cout<<sum[i];
	cout<<endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值