51Nod-1057-N的阶乘

输入N求N的阶乘的准确值。
Input
输入N(1 <= N <= 10000)
Output
输出N的阶乘
Input示例
5
Output示例
120

遇见这道题,也是我的运气,因为以前根本没有想过这种高精度的题还可以这样子做,太神奇了,先发一下我原来的做法。

#include <stdio.h>
#include <string.h>
#define _MAX 6
#define MAX_ 10000000
int product[MAX_];
int pro[MAX_], num[_MAX];
int rank = 1;

//递归进位函数
void Carrying(int tag,int i,int j,int *p)
{
    p[i+j]+=tag;
    if (i + j + 1 > rank || (i + j + 1 == rank && p[i + j] > 9))
    {
        rank++;
    }
    if (p[i+j]>9)
    {
        tag=p[i+j]/10;
        p[i+j] %=10;
        Carrying(tag, i+1, j, p);                                //写成Carrying(tag, i, j+1, p);也成立,为了让i+j递增而已
    }
    return ;
}

//乘法
void multiplication(int N)
{
    int i=0,j=0,numLen,productLen,tag;
    for (i = 0; N > 0; i++)
    {
        num[i] = N % 10;
        N /= 10;
    }
    numLen = i;
    productLen = rank;
    for (i = 0; i < productLen; i++)
    {
        pro[i] = product[i];
    }
    memset(product, 0, sizeof(int) * MAX_);

    //逐位相乘
    for (i=0; i<productLen; i++)
    {
        for (j=0; j<numLen; j++)
        {
            tag= pro[i] *  num[j];
            Carrying(tag, i, j, product);                          //递归
        }
    }
    return ;
}

int main()
{
    int N, i = 2, j;
    scanf("%d", &N);
    memset(product, 0, sizeof(int) * MAX_);                    //初始化product数据为0
    product[0] = 1;
    for (; i <= N; i++)
    {
        multiplication(i);
    }
    //倒序输出结果
    for (j = rank - 1; j >= 0; j--)
    {
        printf("%d",product[j]);
    }
    printf("\n");
}

这种做法比较细碎,所以在这道题的测试数据下,只过了五分之二的测试数据,剩下的悉数超时,所以,我不得不寻求其他更简单的方法,于是乎,就遇见了下面这个巧妙的方法。

#include <stdio.h>
#define _MAX 100000000
int main()
{
    int n, i, j, m;
    long long a[10000], c;
    scanf("%d",&n);

    m = 0;
    a[0] = 1;
    for(i = 1; i <= n; i++)
    {
        c = 0;
        for(j = 0; j <= m; j++)
        {
            a[j] = a[j] * i + c;
            c = a[j] / _MAX;
            a[j] %= _MAX;
        }
        if(c > 0)
        {
            m++;
            a[m] = c;
        }
    }
    printf("%lld", a[m]);
    for(i = m - 1; i >= 0; i--)
        printf("%0.8lld", a[i]);
    printf("\n");
    return 0;
}

这里我们知道,如果简单的用乘法去阶乘,那么不用多大,立马就爆了数据范围,于是,这道题的这个解法巧妙的对这个超级大的数进行了切分,具体切成多宽的看个人爱好,只要能够用几个数据类型装下来就好,这里我们划分成了8个的宽度,每八位存一下,最后再进行格式化输出,巧妙的避开了爆数据范围的问题。看着代码理解起来并不难,提示一下,c和进位相关,m和切的段数相关,就这样,相信大家看看都是可以理解的,如果无法理解,那么只能说,回去学学数学吧,乖Y(^_^)Y!!!

你可能感兴趣的:(阶乘,高精度,切割)