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!!!