题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1042
N!
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24886 Accepted Submission(s): 6897
Problem Description
Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N!
Input
One N in one line, process to the end of file.
Output
For each N, output N! in one line.
Sample Input
1 2 3
Sample Output
1 2 6
解题思路
: 算法来源于一篇博客的介绍---“列表法”。http://blog.csdn.net/amossavez/article/details/4312399
也就是说我们在计算生成这个二维表时,不必一位一位地乘,而可以三位三位地乘;在累加时也是满1000进位。这样,我们在计算 m位整数乘以 n位整数,只需要进行 m x n / 9次乘法运算,再进行约(m + n) / 3次加法运算和(m + n) /3 次取模运算。总体看来,效率约是前一种算法的 9倍。
有人可能会想:既然能够三位三位地乘,为什么不4位 4位甚至5位5位地乘呢?那不是可以提高 16 乃至 25 倍效率吗?听我解来:本算法在累加表中斜线间的数字时,如果用无符号长整数(范围 0至~4294967295)作为累加变量,在最不利的情况下(两个乘数的所有数字均是 9),能够累加约4294967295/(999*999)=4300 次,也就是能够准确计算任意两个均不超过 12900(每次累加的结果"值"三位,故 4300*3=12900)位的整数相乘。如果 4 位 4 位地乘,在最不利的情况下,能够累加约4294967295/(9999*9999)=43 次,仅能够确保任意两个不超过 172 位的整数相乘,没有什么实用价值,更不要说5位了。
有人可能会想:既然能够三位三位地乘,为什么不4位 4位甚至5位5位地乘呢?那不是可以提高 16 乃至 25 倍效率吗?听我解来:本算法在累加表中斜线间的数字时,如果用无符号长整数(范围 0至~4294967295)作为累加变量,在最不利的情况下(两个乘数的所有数字均是 9),能够累加约4294967295/(999*999)=4300 次,也就是能够准确计算任意两个均不超过 12900(每次累加的结果"值"三位,故 4300*3=12900)位的整数相乘。如果 4 位 4 位地乘,在最不利的情况下,能够累加约4294967295/(9999*9999)=43 次,仅能够确保任意两个不超过 172 位的整数相乘,没有什么实用价值,更不要说5位了。
倒序存储:如res[]={312,658,7} two[]={564,2}
代码如下:
#include <iostream>
#include <iomanip>
using namespace std;
unsigned int *res,*temp;
int two[2];
int digit;
void mult(int x)
{
int twoN;
unsigned int *p=0;
if(x>999){two[0]=x%1000;two[1]=x/1000;twoN = 2;}
else{two[0]=x;twoN=1;}
int c=0;
int i,j,maxj;
//cout<<"two: "<<two[0]<<","<<two[1]<<" --"<<twoN<<endl;
for(i=0;i<digit+twoN-1;i++)
{
if(i-digit+1>0)j=i-digit+1;
else j=0;
maxj = i+1 > twoN ? twoN:i+1;
for(;j<maxj;j++)
{
c = c + two[j]*res[i-j];
}
temp[i]=c%1000;
c = c/1000;
//cout<<">>>> i:"<<i<<" temp[i]:"<<temp[i]<<endl;
}
if(c){temp[i]=c;digit=i+1;}
else digit=i;
p=res;
res=temp;
temp=p;
}
int main()
{
//freopen("out.txt","w",stdout);
int n,i;
res=(unsigned int *)malloc(sizeof(int)*15000);
temp=(unsigned int *)malloc(sizeof(int)*15000);
while(cin>>n)
{
if(n==0){cout<<1<<endl;continue;}
memset(res,0,sizeof(int)*15000);
if(n>999){res[0]=n%1000;res[1]=n/1000;digit=2;}
else {res[0] = n;digit = 1;}
for(i=n-1;i>1;i--)
{
mult(i);
}
//cout<<"digit:"<<digit<<endl;
cout<<res[digit-1];
for(i=digit-2;i>=0;i--)
{ cout<<setfill('0')<<setw(3)<<res[i]; }
cout<<endl;
}
return 0;
}