题目描述
用高精度计算出 S = 1! + 2! + 3! + … + n! ( n <= 50 )。
其中 !
表示阶乘,定义为 n!=n (n-1) (n-2) … 1 。例如, 5! = 5 4 3 2 1=120 。
输入格式
一个正整数 n 。
输出格式
一个正整数 S ,表示计算结果。
样例 #1
样例输入 #1
3
样例输出 #1
9
提示
【数据范围】
对于 100 % 的数据, 1 <= n <= 50 。
思路
看了一下大部分题解,其实也没有别的考察点,主要就是高精加套高精乘,方法也有很多,下面主要介绍两种该思路的实现方法
方法一
这种方法主要使用结构体去封装大整数,让大整数能像普通整型一样直接相加相乘,下面是封装的结构体
#define MAXN 50000
struct bigint{
int len,a[MAXN];//len记录位数,a记录每个数位
bigint(int x=0){//通过初始化使得这个大整数能够表示整型x,默认为0
memset(a,0,sizeof(a));
for(len=1;x;len++){
a[len]=x%10,x/=10;
}
len--;
}
int &operator[](int i){
return a[i]; //重载[],可以直接用x[i]代表x.a[i]
}
void flatten(int L){//一口气处理1到L范围内的进位并重置长度。需要保证L不小于有效长度
//简单说就是将数组每个位置经过进位后都变成一位数
len=L;
for(int i=1;i<=len;i++){
a[i+1]+=a[i]/10;
a[i]%=10;
}
for(;!a[len];){//重置长度为有效长度
len--;
}
}
void print(){
for(int i=max(len,1);i>=1;i--){
printf("%d",a[i]);
}
}
bigint operator+(bigint a,bigint b){//表示两个bigint类相加,返回一个bigint类
bigint c;
int len=max(a.len,b.len);
for(int i=1;i<=len;i++){
c[i]+=a[i]+b[i];
}
c.flatten(len+1);//答案不可能超过len+1位,所以用len+1做进位处理
return c;
}
bigint operator*(bigint a,bigint b){
bigint c;
int len=a.len;
for(int i=1;i<=len;i++){
c[i]=a[i]*b;
}
c.flatten(len+1);//int类型最长10位,所以可以这样做一遍进位处理
}
};
封装完后,就需要主函数对接接口直接使用了
int main(){
bigint ans(0),fac(1);//分别用0,1初始化ans和fac,如果要将常数赋值给大整数,可以使用类似于ans=bigint(233)的办法
int m;
cin>>m;
while(m--){
fac*=i;
ans+=fac;
} ans.print();
}
代码来源——《深入浅出——程序设计竞赛(基础篇)》
有没有发现什么问题?如果你拿上面的代码去提交的话,大概率是不会通过原题OJ的。原因出在哪呢?
关键就在于当阶乘数不断变大,构造函数的输入接口x就无法承载下更大数字。经过官方测试的结果,上面代码只能承载n<=20的结果。
如果还是要用上面的方法,那么接口也需要进行高精度处理。我个人的解决方案有两种:
一是将接口类型也修改为bigint,然后将原构造函数的内容转移到另一个功能函数进行位数处理,新的构造函数采用流输入来将接受大整数并直接读入数组。但实现起来比较麻烦。
另一种则是将大整数当成字符串读入,修改原接口类型为string或char数组,逐一放进结构体中处理成数字即可
方法二
我个人更喜欢自己的方法,同样拥有上述结构体中的功能,而且实现起来也更加便捷
#include<stdio.h>
int main()
{
int i,A[1005]={0},B[1005]={0},n,j;
scanf("%d", &n);
A[0]=B[0]=1;
for (i=2;i<=n;i++){
for (j=0;j<100;j++)
B[j]*=i;
for (j=0;j<100;j++)
if (B[j]>9){
B[j+1] += B[j]/10;
B[j]%=10;
}
for (j=0;j<100;j++){
A[j]+=B[j];
if (A[j]>9) {
A[j+1] += A[j]/10;
A[j]%=10;
}
}
}
for (i=100;i>=0&&A[i]==0;i--);
for (j=i;j>=0;j--) printf("%d", A[j]);
return 0;
}