hdu1042 N!

题目链接

N!这个题目在算法竞赛入门经典  出现过,过程相当于模拟手算的过程(我的大数乘法也是这样的)。假使我们的现在知道(n-1)! ,那么n!=(n-1)!*n.这个也是显而易见的。

但是n!的结果十分的大,10000!差不多需要45000位数字。所以我们不能简单的使用一个基础类型去进行存储,所以我们想到了另一个东西--------数组,对,没错就是数组,我们可以模拟我们手算的方式来进行计算。

假设我们要求解7!,已知6!,手算过程如下

6!=720.

            7           2          0

    *                                7

--------------------------------

                                      0

               1        4

    4         9

------------------------------------

   5           0        4            0

这个过程相当简单,我们也就是拿7和6!的每一位相乘,然后按照位置加下来就可以了。当然写程序一般我们不会那么做,我们先将乘数与被乘数的第i位相乘得到的结果和上一次的进位结果加起来与10取模(既是求得当前位),放在存储结果的数组的第i位中,记录这次运算的进位(结果除以10就是进位结果),这样循环即可。


上面的描述可能太过于繁琐看代码好些。

    
    result[0]=1;//result是存储结果的数组
                //我们存放的顺序是逆序的,以便于我们进位,例如6!=720,你们result存放的是 result[0]=0,result[1]=2,result[2]=7;
 for(int i=2;i<=n;i++)
    {
        int t=0;//进位结果,初始化进位为0
        for(int j=0;j<MAXN;j++)
        {
            int temp=result[j]*i+t;//被乘数的第i位与乘数相乘加上进位的结果
            result[j]=temp%10;//实际上存储的第i位的大小
            t=temp/10000;//取得这次运算的进位结果
        }
    }
//输出的时候逆序输出即可,记得处理前导零

这样做是没有问题的。但是面对hdu1042需要求10000!这么搞?我一开始使用上面的方法做,果断的TLE(超时),看了别人的一些资料后发现,还可以对上面的代码进行改进。我们可以观察,我们的result数组只存一位,那如果我们的result存的不是一位而是几位是不是会使我们的计算次数变少?怎么做?其实也就是简简单单改一下代码中mod的数和除的数。

result[0]=1;
    for(int i=2;i<=n;i++)
    {
        int t=0;
        int k=0;
        for(int j=0;j<MAXN;j++)
        {
            int temp=result[j]*i+t;
            result[j]=temp%10000;//改了这儿
            t=temp/10000;//改了这儿
        }
    }


我们这样做为什么是正确的?其实我们也就是把一个数分成了几块来运算而已 ,第一段代码我们使用一块一位,现在我们是一块4位进行计算,进位也是一样。其实是进制的转换,我们从10进制的计算到了万进制的转换。

Q:上面提到的是4位一块,那能不能在提高欸例如6位7位?

A:可以的,分几块基于基础的数据类型,假设你使用int定义一个块,那么必须保证两个块的最大值相乘能够被一个int装起来,不会出现溢出。所以int可以装5位,如果6位和6位会超,可以选用64位整形存储。位数可达9位。


注意:注意多位存储的时候注意0的输出

贴下我的代码:

#include <iostream>
#include <stdio.h>
#include <cstring>
using namespace std;

const int MAXN=20000;

int result[MAXN];

void fac(int n)
{
    memset(result,0,sizeof(result));
    result[0]=1;
    for(int i=2;i<=n;i++)
    {
        int t=0;
        int k=0;
        for(int j=0;j<MAXN;j++)
        {
            int temp=result[j]*i+t;
            result[j]=temp%10000;
            t=temp/10000;

        }
    }
    int i=MAXN-1;
    for(;!result[i];i--);
    cout<<result[i];
    for(i-=1;i>=0;i--)
    {
       if(result[i]<10){
            cout<<"000";
       }
       else if(result[i]<100){
            cout<<"00";
       }
       else if(result[i]<1000){
            cout<<"0";
       }
       cout<<result[i];
    }
    cout<<endl;
}


int main()
{
    int n;
    while(cin>>n)
    {
        fac(n);
    }
    return 0;
}

已经ac。

如果我的这篇文中出现什么问题,欢迎批评指正。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值