[高精度加法和乘法] 阶乘之和

题目描述

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

其中 ! 表示阶乘,定义为 n!=n×(n−1)×(n−2)×⋯×1。例如,5!=5×4×3×2×1=120。

输入格式

一个正整数 n。

输出格式

一个正整数 S,表示计算结果。

输入输出样例

输入 #1

3

输出 #1

9
解题分析

思路很简单,求出阶乘之后再累次求和即可,但是关键在于这个数据量实在是太大了,所以必须封装高精度运算,这里我们创建一个BigInt类,然后重载运算符+和*,得出答案即可。

这段代码定义了一个 BigInt 类来处理大整数的运算,这对于计算大数的阶乘和它们的和是必需的,因为标准的整型变量无法存储这么大的数字。接下来,我们会逐步解释关键的组成部分,尤其是高精度的加法和乘法。

构造函数

BigInt 类有两个构造函数,分别接受一个整数和一个字符串作为参数。整数构造函数将整数转换为字符数组(字符串表示),而字符串构造函数则直接复制给定的字符串到内部字符数组。转换整数时,采用逆序存储的方式,方便后续的加法和乘法运算。

高精度加法

高精度加法的实现在 operator+ 函数中。它首先将两个大整数的字符串表示逆序存储到整型数组中,然后逐位相加,并处理进位。由于加法可能导致结果的位数增加(例如,999 + 1 = 1000),因此需要预留足够的空间并在最后处理进位。加法完成后,将得到的数字逆序转换成字符串形式,得到最终的加法结果。

高精度乘法

高精度乘法的实现在 operator* 函数中。该函数使用了一个简单的乘法运算法则,即对于两个数的每一位相乘,并将结果累加到正确的位置上。这里同样使用了逆序存储和处理进位。乘法的复杂度较高,因为它涉及到双层循环,每一位的乘积都需要计算并累加进位。

阶乘与求和

factorial 函数计算给定整数的阶乘,通过从 2 乘到 n 的方式,使用前面定义的高精度乘法。

main 函数中,读取用户输入的 n,然后从 1 遍历到 n,计算每个数的阶乘,并使用高精度加法将它们累加起来。最终,将结果输出。

示例

对于输入 3,计算 1! + 2! + 3! 的结果:

  1. 1! = 1
  2. 2! = 2
  3. 3! = 6

因此,1! + 2! + 3! = 9

这段代码通过高精度运算支持了对大数的阶乘及其和的计算,解决了标准数据类型无法处理大数运算的问题。

代码实现
#include <iostream>
#include <cstring>
#include <iomanip>
using namespace std;
class BigInt{
public:
	char s[3000];
	BigInt(int n){
		char c;
		int k=0;
		if(n==0){
			s[0]='0';
			s[1]='\0';
			k=1;
		}
		while(n){
			c=n%10+'0';
			s[k++]=c;
			n/=10;
		}
		s[k]='\0';
		for(int i=0,j=k-1;i<=j;i++,j--){
			c=s[i];
			s[i]=s[j];
			s[j]=c;
		}
	}
	BigInt(const char *s1){
		strcpy(s,s1);
	}
	BigInt operator+(const BigInt &b){
		int lena=strlen(s);
		int lenb=strlen(b.s);
		int a1[3000],b1[3000],c[3000]={0};
		for(int i=0,j=lena-1;i<lena;i++,j--){
			a1[i]=s[j]-'0';
		}
		for(int i=0,j=lenb-1;i<lenb;i++,j--){
			b1[i]=b.s[j]-'0';
		}
		int len=lena+lenb;
		int tmp=0;
		for(int i=0;i<len;i++){
			c[i]=a1[i]+b1[i]+tmp;
			tmp=c[i]/10;
			c[i]%=10;
		}
		char ans[3000];
		int pos=0;
		for(int i=len;i>=0;i--){
			if(c[i]){
				pos=i+1;
				break;
			}
		}
		for(int i=0,j=pos-1;i<pos;i++,j--){
			ans[i]=c[j]+'0';
		}
		ans[pos]='\0';
		if(pos==0){
			ans[0]='0';
			ans[1]='\0';
		}
		return BigInt(ans);
	}
	BigInt operator*(const BigInt &b){
		int lena=strlen(s);
		int lenb=strlen(b.s);
		int a1[3000],b1[3000],c[3000]={0};
		for(int i=0,j=lena-1;i<lena;i++,j--){
			a1[i]=s[j]-'0';
		}
		for(int i=0,j=lenb-1;i<lenb;i++,j--){
			b1[i]=b.s[j]-'0';
		}
		int len=lena+lenb+2;
		int jw;
		for(int i=0;i<lena;i++){
			jw=0;
			for(int j=0;j<lenb;j++){
				c[i+j]+=a1[i]*b1[j]+jw;
				jw=c[i+j]/10;
				c[i+j]%=10;
			}
			c[i+lenb]=jw;
		}
		char ans[3000];
		int pos=0;
		for(int i=len;i>=0;i--){
			if(c[i]){
				pos=i+1;
				break;
			}
		}
		for(int i=0,j=pos-1;i<pos;i++,j--){
			ans[i]=c[j]+'0';
		}
		ans[pos]='\0';
		if(pos==0){
			ans[0]='0';
			ans[1]='\0';
		}
		return BigInt(ans);
	}
};

BigInt factorial(int n){
	BigInt ans(1);
	for(int i=2;i<=n;i++){
		ans=ans*BigInt(i);
	}
	return ans;
}


int main(){
	BigInt res(0);
	int n; cin>>n;
	for(int i=1;i<=n;i++){
		res=res+factorial(i);
	}
	cout<<res.s<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值