蓝桥杯C++:BASIC30 阶层计算

关键词:高精度

问题描述:
输入一个正整数n,输出n!的值。
其中n!=123*…*n。
输入格式:
输入包含一个正整数n,n<=1000。
输出格式:
输出n!的准确值。
算法描述:
n!可能很大,而计算机能表示的整数范围有限,需要使用高精度计算的方法。使用一个数组A来表示一个大整数a,A[0]表示a的个位,A[1]表示a的十位,依次类推。
将a乘以一个整数k变为将数组A的每一个元素都乘以k,请注意处理相应的进位。
首先将a设为1,然后乘2,乘3,当乘到n时,即得到了n!的值。

解题思路:
在C++中,对数值型和字符型的空间所能存储的数值范围有限制,这道题除了考“算法描述”里的算法实现外,也考察了如何用整型数组存储一个数值较大的整数。
我跟着“算法描述”中的思路进行了实现,实现的难点是处理进位问题,即当数组中某一元素大于10时,如何实现将非个位的数值转存至高位,使得每个元素中只存储一个数值(0-9);与此同时需要注意的是,是否又新占用了数组中的空间(即n!的位数较(n-1)!的位数有所增加)。
亲测,用一个含2600个元素的整型数组即可实现对1000!的存储,如int a[MaxSize]。
注意点:
(1)在开始时需要将数组中的每个元素初始化为0,否则系统会随机为这些元素分配值。可导入库中的memset函数对数组进行初始化。
(2)存n!不一定会用到MaxSize个元素,可设置一个名为index的整型变量来标记有效的存储空间,令a[index]=-1,当程序碰到它时,即可知道这之后的元素还未用于存数。

代码实现:
在这里插入图片描述

#include <iostream>
#define MaxSize 2600
using namespace std;

int main()
{
    int a[MaxSize];
    int n;
    cin>>n;
    int i,j,t,temp,index=1;
    for(i=2;i<MaxSize;i++)
        a[i]=0;
    a[0]=1;a[index]=-1;
    for(i=2;i<=n;i++){
        for(j=0;j<index;j++){
            a[j]=a[j]*i;
        }
        for(j=0;j<index;j++){
            t=0;
            temp=a[j];
            while(temp>0){
                if(a[j+t]==-1){
                    a[j+t+1]=-1;
                    a[j+t]=0;
                    index++;
                }
                if(t==0)
                    a[j+t]=temp%10;
                else
                    a[j+t]+=temp%10;
                temp=temp/10;
                t++;
            }
        }
    }
    for(i=index-1;i>=0;i--)
        cout<<a[i];
    cout<<endl;

    return 0;
}

在最开始时,我并没用a[index]=-1来进行标记,这样运行出的代码只对100以下的阶层有效。后来分析了一下原因,存储位数的增加并不仅限于对最后一个a[j}进行进位处理时,可能在对a[j-2],a[j-1]进行进位操作时存储位数就已经于原来的j为,故对每一个a[j]都需要检查index,a[index]是否需要更新。
下面是错误的代码:

#include <iostream>
#define MaxSize 2700
using namespace std;

int main()
{
    int a[MaxSize];
    int n;
    cin>>n;
    int i,j,k,t,temp,index=1;
    for(i=1;i<MaxSize;i++)
        a[i]=0;
    a[0]=1;
    for(i=2;i<=n;i++){
        for(j=0;j<index;j++){
            a[j]=a[j]*i;
        }
        for(k=0;k<j;k++){
            t=0;
            temp=a[k];
            while(temp>0){
                if(t==0)
                    a[k+t]=temp%10;
                else
                    a[k+t]+=temp%10;
                temp=temp/10;
                t++;
            }
        }

        if(k==j && t>0)
            index=k+t-1;
    }
    for(i=index-1;i>=0;i--)
        cout<<a[i];
    cout<<endl;

    return 0;
}

输入输出样例:
input1:
1
output1:
1

input5:
50
output5:
30414093201713378043612608166064768844377641568960512000000000000

input7:
312
output7:
210202660512637835935172644211957133627043908720000167536756842728609276364870071276018632900069284700768301037938261101173961429020590768649673393745350229366900929723019237747008737725622726743681331817177398316310598929099640952146939184746561215434218580476712209164729840218710611141997608556081517114151978078529649675756198677900973955961088376590768187445187161362720223207506081889280736666374823205851569546732513468951411991741029659341762512184725306790769924064352250767773275338247678425384558165880296838989360876451983191202726095516684776830265993461760000000000000000000000000000000000000000000000000000000000000000000000000000

intput10:
1000
output10:
402387260077093773543702433923003985719374864210714632543799910429938512398629020592044208486969404800479988610197196058631666872994808558901323829669944590997424504087073759918823627727188732519779505950995276120874975462497043601418278094646496291056393887437886487337119181045825783647849977012476632889835955735432513185323958463075557409114262417474349347553428646576611667797396668820291207379143853719588249808126867838374559731746136085379534524221586593201928090878297308431392844403281231558611036976801357304216168747609675871348312025478589320767169132448426236131412508780208000261683151027341827977704784635868170164365024153691398281264810213092761244896359928705114964975419909342221566832572080821333186116811553615836546984046708975602900950537616475847728421889679646244945160765353408198901385442487984959953319101723355556602139450399736280750137837615307127761926849034352625200015888535147331611702103968175921510907788019393178114194545257223865541461062892187960223838971476088506276862967146674697562911234082439208160153780889893964518263243671616762179168909779911903754031274622289988005195444414282012187361745992642956581746628302955570299024324153181617210465832036786906117260158783520751516284225540265170483304226143974286933061690897968482590125458327168226458066526769958652682272807075781391858178889652208164348344825993266043367660176999612831860788386150279465955131156552036093988180612138558600301435694527224206344631797460594682573103790084024432438465657245014402821885252470935190620929023136493273497565513958720559654228749774011413346962715422845862377387538230483865688976461927383814900140767310446640259899490222221765904339901886018566526485061799702356193897017860040811889729918311021171229845901641921068884387121855646124960798722908519296819372388642614839657382291123125024186649353143970137428531926649875337218940694281434118520158014123344828015051399694290153483077644569099073152433278288269864602789864321139083506217095002597389863554277196742822248757586765752344220207573630569498825087968928162753848863396909959826280956121450994871701244516461260379029309120889086942028510640182154399457156805941872748998094254742173582401063677404595741785160829230135358081840096996372524230560855903700624271243416909004153690105933983835777939410970027753472000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

附:
memset用法示例:
(memset()方法可用于初始化整型数组和字符数组)

#include<iostream>
#include<cstring>
using namespace std;

int main()
{
	int a[10];
	/*初始化整型数组*/
	memset(a,0,sizeof(a)); 
	int i;
	for(i=0;i<10;i++)
        cout<<a[i]<<' ';
    cout<<endl;
    char str[30];
	//char *s=str;
	/*初始化字符型数组 (第一个参数可用指针代替)*/
	memset(str,'G',sizeof(str)); 
	cout<<str<<endl;

	return 0;
}

运行结果:
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值