P1009 [NOIP 1998 普及组] 阶乘之和
题目描述
用高精度计算出 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
说明/提示
【数据范围】
对于 100% 的数据,1≤n≤50。
【其他说明】
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n≤20,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
NOIP1998 普及组 第二题
解题方法:
用高精度加法和高精度乘法结合做。
我们先讲一下为什么用和怎么用高精度加法和乘法;
为什么用高精度加法和乘法:
因为每一个变量类型都是有取值范围的,例如:int型(-2^31~2^31-1),就算是long long型也就(-2^63~2^63-1),所以当数字过大时就容易发生溢出。这里就需要用到高精度加法和高精度乘法。
如何使用高精度加法和乘法:
高精度加法:
1.用两个整型数组分别存储加数和被加数,
先用char数组存储再转为long long数组【reverse就是逆转一下数组】
char str1[500],str2[500];cin>>str1>>str2;long long len1,len2,lenmax,h;len1=strlen(str1);len2=strlen(str2);reverse(str1,str1+len1);reverse(str2,str2+len2);lenmax=len1>len2?len1:len2;vector<long long> array1(500,0);vector<long long> array2(500,0);vector<long long> array(500,0);for(long long i=0;i<lenmax;i++){if(i<len1){array1[i]=str1[i]-'0';}if(i<len2){array2[i]=str2[i]-'0';}}
2.两整型数组中的从低到高的单个数字依次相加,并进位 ,
例如23+99:就是3+9=2进位1,2+9+1=2,进位1;
for(long long i=0;i<lenmax;i++){array[i]+=(array1[i]+array2[i])%10;array[i+1]+=(array1[i]+array2[i])/10;}if(array[lenmax]){lenmax++;}for(long long i=lenmax-1;i>=0;i--){cout<<array[i];}
高精度乘法:
1.用两个整型数组分别存储乘数和被乘数,
先用char数组存储再转为long long数组【reverse就是逆转一下数组】
char str1[500],str2[500];cin>>str1>>str2;long long len1,len2,lenmax,h;len1=strlen(str1);len2=strlen(str2);reverse(str1,str1+len1);reverse(str2,str2+len2);lenmax=len1>len2?len1:len2;vector<long long> array1(500,0);vector<long long> array2(500,0);vector<long long> array(500,0);for(long long i=0;i<lenmax;i++){if(i<len1){array1[i]=str1[i]-'0';}if(i<len2){array2[i]=str2[i]-'0';}}
2.一整型数组中的每一个数字从低到高依次乘以别一数组中的每一个数字。
最终得到的数组中的每一个数字都%10并且进位(/10)
例如:123*321 得数组中第一个a[0]为3*1=3 ,a[1]=2*1+3*2=8 ,a[2]=3*3+2*2+1*1=14等等。
lenmax=len1+len2;for(long long i=0;i<len1;i++){for(long long j=0;j<len2;j++){array[i+j]+=array1[i]*array2[j];}}for(long long i=0;i<lenmax;i++){array[i+1]+=array[i]/10;array[i]=array[i]%10;}if(!array[lenmax-1]){lenmax--;}for(long long i=lenmax-1;i>=0;i--){cout<<array[i];}
那么现在讲讲如何做这一题:
1.首先用高精度乘法计入n个大数字于long long 数组中并且依次计入每一个大数字分别有多少位
例如有3个大数字时,1在a[0][0]中有1位,2在a[1][0]中有1位,6在a[2][0]中有1位,
long long n,length=1;cin>>n;vector<vector<long long> > array(n,vector<long long>(500,0));//array存储的是每一个大数据vector<long long> number(n,0);array[0][0]=1;number[0]=1;//number存储的是每一个大数据有多少位for(long long i=2;i<=n;i++){for(long long j=0;j<length;j++){array[i-1][j]=array[i-2][j]*i;}length+=2;for(long long j=0;j<length;j++){array[i-1][j+1]+=array[i-1][j]/10;array[i-1][j]%=10;}while(1){if(array[i-1][length-1]){break;}else{length--;}}number[i-1]=length;}
2.再用高精度加法对每一个大数据进行相加。【我这里是将array[0]以后的大数据都加在array[0]中,所以array[0]是最终相加数】
for(long long i=1;i<n;i++){for(long long j=0;j<number[i];j++){array[0][j+1]+=(array[0][j]+array[i][j])/10;array[0][j]=(array[0][j]+array[i][j])%10;}}length=number[n-1];if(array[0][length]){length++;}for(long long i=length-1;i>=0;i--){cout<<array[0][i];}
总体代码:
#include<bits/stdc++.h>
using namespace std;
int main(){long long n,length=1;cin>>n;vector<vector<long long> > array(n,vector<long long>(500,0));vector<long long> number(n,0);array[0][0]=1;number[0]=1;for(long long i=2;i<=n;i++){for(long long j=0;j<length;j++){array[i-1][j]=array[i-2][j]*i;}length+=2;for(long long j=0;j<length;j++){array[i-1][j+1]+=array[i-1][j]/10;array[i-1][j]%=10;}while(1){if(array[i-1][length-1]){break;}else{length--;}}number[i-1]=length;}for(long long i=1;i<n;i++){for(long long j=0;j<number[i];j++){array[0][j+1]+=(array[0][j]+array[i][j])/10;array[0][j]=(array[0][j]+array[i][j])%10;}}length=number[n-1];if(array[0][length]){length++;}for(long long i=length-1;i>=0;i--){cout<<array[0][i];}return 0;
}
以上就是P1009 [NOIP 1998 普及组] 阶乘之和的详细作法,希望对大家有所帮助。