原帖链接:http://www.cnblogs.com/kym/archive/2009/10/05/1578224.html
我机器上没有C#的开发环境,所以没法测试作者这个代码的耗时,不过10000的阶乘在5秒内完成,不知道作者的代码是否能达到?我想起前段时间在HDU做的一道ACM题,题目的时限要求是1秒内能计算10000的阶乘(当然这是代码跑在它的服务器的时间)。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1042
如果按照飞林沙文章中那种常规的思路,逐位相乘,再对齐相加,缺点很明显,如果n值比较大,运算次数将非常多,必定会超时,1万的阶乘想在1秒内完成肯定无法达成。
我的思路是把数据分组,每组上限为9999,最多可容纳2万组,每组4位整数,则可以容纳8万位整数(当然,组数可以随你要计算的n的大小进行调整),利用组与组的错位相乘再相加,可以避免楼主这样逐位进行运算。
代码如下:
#include
<
iostream
>
#include < stdio.h >
#include < string >
#include < iomanip >
#include < algorithm >
using namespace std;
#include " time.h "
const int MAX_GROUPS = 20000 ; // 最多2万组,每组最多4位整数,即最多可容纳8万位整数
const int MAXN = 9999 ; // 每组的上限值
const int GROUP_LEN = 4 ; // 每组的最大长度
class BigInteger
{
private :
int data[MAX_GROUPS];
int len;
void init()
{
memset(data, 0 , sizeof (data));
}
public :
BigInteger()
{
init();
len = 0 ;
}
BigInteger( const int b);
BigInteger( const BigInteger & );
bool operator > ( const BigInteger & ) const ;
BigInteger & operator = ( const BigInteger & );
BigInteger & add( const BigInteger & );
BigInteger & sub( const BigInteger & );
BigInteger operator + ( const BigInteger & ) const ;
BigInteger operator - ( const BigInteger & ) const ;
BigInteger operator * ( const BigInteger & ) const ;
BigInteger operator / ( const int & ) const ;
void print();
};
BigInteger::BigInteger( const int num)
{
int res,tmp = num;
len = 0 ;
init();
while (tmp > MAXN)
{
res = tmp - tmp / (MAXN + 1 ) * (MAXN + 1 );
tmp = tmp / (MAXN + 1 );
data[len ++ ] = res;
}
data[len ++ ] = tmp;
}
BigInteger::BigInteger( const BigInteger & rhs) : len(rhs.len)
{
int i;
init();
for (i = 0 ; i < len ; i ++ )
{
data[i] = rhs.data[i];
}
}
bool BigInteger:: operator > ( const BigInteger & rhs) const
{
int ln;
if (len > rhs.len)
{
return true ;
}
else if (len < rhs.len)
{
return false ;
}
else if (len == rhs.len)
{
ln = len - 1 ;
while (data[ln] == rhs.data[ln] && ln >= 0 )
{
ln -- ;
}
if (ln >= 0 && data[ln] > rhs.data[ln])
{
return true ;
}
else
{
return false ;
}
}
}
BigInteger & BigInteger:: operator = ( const BigInteger & rhs)
{
init();
len = rhs.len;
for ( int i = 0 ; i < len ; i ++ )
{
data[i] = rhs.data[i];
}
return * this ;
}
BigInteger & BigInteger::add( const BigInteger & rhs)
{
int i,nLen;
nLen = rhs.len > len ? rhs.len : len;
for (i = 0 ; i < nLen ; i ++ )
{
data[i] = data[i] + rhs.data[i];
if (data[i] > MAXN)
{
data[i + 1 ] ++ ;
data[i] = data[i] - MAXN - 1 ;
}
}
if (data[nLen] != 0 )
{
len = nLen + 1 ;
}
else
{
len = nLen;
}
return * this ;
}
BigInteger & BigInteger::sub( const BigInteger & rhs)
{
int i,j,nLen;
if (len > rhs.len)
{
for (i = 0 ; i < nLen ; i ++ )
{
if (data[i] < rhs.data[i])
{
j = i + 1 ;
while (data[j] == 0 ) j ++ ;
data[j] -- ;
-- j;
while (j > i)
{
data[j] += MAXN;
-- j;
}
data[i] = data[i] + MAXN + 1 - rhs.data[i];
}
else
{
data[i] -= rhs.data[i];
}
}
len = nLen;
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
else if (len == rhs.len)
{
for (i = 0 ; i < len ; i ++ )
{
data[i] -= rhs.data[i];
}
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
return * this ;
}
BigInteger BigInteger:: operator + ( const BigInteger & n) const
{
BigInteger a = * this ;
a.add(n);
return a;
}
BigInteger BigInteger:: operator - ( const BigInteger & T) const
{
BigInteger b = * this ;
b.sub(T);
return b;
}
BigInteger BigInteger:: operator * ( const BigInteger & rhs) const
{
BigInteger result;
int i,j,up;
int temp,temp1;
for (i = 0 ; i < len; i ++ )
{
up = 0 ;
for (j = 0 ; j < rhs.len; j ++ )
{
temp = data[i] * rhs.data[j] + result.data[i + j] + up;
if (temp > MAXN)
{
temp1 = temp - temp / (MAXN + 1 ) * (MAXN + 1 );
up = temp / (MAXN + 1 );
result.data[i + j] = temp1;
}
else
{
up = 0 ;
result.data[i + j] = temp;
}
}
if (up != 0 )
{
result.data[i + j] = up;
}
}
result.len = i + j;
while (result.data[result.len - 1 ] == 0 && result.len > 1 ) result.len -- ;
return result;
}
BigInteger BigInteger:: operator / ( const int & b) const
{
BigInteger ret;
int i,down = 0 ;
for (i = len - 1 ; i >= 0 ; i -- )
{
ret.data[i] = (data[i] + down * (MAXN + 1 )) / b;
down = data[i] + down * (MAXN + 1 ) - ret.data[i] * b;
}
ret.len = len;
while (ret.data[ret.len - 1 ] == 0 ) ret.len -- ;
return ret;
}
void BigInteger::print()
{
int i;
cout << data[len - 1 ];
for (i = len - 2 ; i >= 0 ; i -- )
{
cout.width(GROUP_LEN);
cout.fill( ' 0 ' );
cout << data[i];
}
cout << endl;
}
int main()
{
clock_t start, finish;
double duration;
int i,n;
BigInteger result,num;
scanf( " %d " , & n);
start = clock();
result = BigInteger( 1 );
for (i = 2 ;i <= n; ++ i)
{
num = BigInteger(i);
result = result * num;
}
result.print();
finish = clock();
duration = ( double )(finish - start) / CLOCKS_PER_SEC;
printf( " %f seconds/n " , duration );
return 0 ;
}
#include < stdio.h >
#include < string >
#include < iomanip >
#include < algorithm >
using namespace std;
#include " time.h "
const int MAX_GROUPS = 20000 ; // 最多2万组,每组最多4位整数,即最多可容纳8万位整数
const int MAXN = 9999 ; // 每组的上限值
const int GROUP_LEN = 4 ; // 每组的最大长度
class BigInteger
{
private :
int data[MAX_GROUPS];
int len;
void init()
{
memset(data, 0 , sizeof (data));
}
public :
BigInteger()
{
init();
len = 0 ;
}
BigInteger( const int b);
BigInteger( const BigInteger & );
bool operator > ( const BigInteger & ) const ;
BigInteger & operator = ( const BigInteger & );
BigInteger & add( const BigInteger & );
BigInteger & sub( const BigInteger & );
BigInteger operator + ( const BigInteger & ) const ;
BigInteger operator - ( const BigInteger & ) const ;
BigInteger operator * ( const BigInteger & ) const ;
BigInteger operator / ( const int & ) const ;
void print();
};
BigInteger::BigInteger( const int num)
{
int res,tmp = num;
len = 0 ;
init();
while (tmp > MAXN)
{
res = tmp - tmp / (MAXN + 1 ) * (MAXN + 1 );
tmp = tmp / (MAXN + 1 );
data[len ++ ] = res;
}
data[len ++ ] = tmp;
}
BigInteger::BigInteger( const BigInteger & rhs) : len(rhs.len)
{
int i;
init();
for (i = 0 ; i < len ; i ++ )
{
data[i] = rhs.data[i];
}
}
bool BigInteger:: operator > ( const BigInteger & rhs) const
{
int ln;
if (len > rhs.len)
{
return true ;
}
else if (len < rhs.len)
{
return false ;
}
else if (len == rhs.len)
{
ln = len - 1 ;
while (data[ln] == rhs.data[ln] && ln >= 0 )
{
ln -- ;
}
if (ln >= 0 && data[ln] > rhs.data[ln])
{
return true ;
}
else
{
return false ;
}
}
}
BigInteger & BigInteger:: operator = ( const BigInteger & rhs)
{
init();
len = rhs.len;
for ( int i = 0 ; i < len ; i ++ )
{
data[i] = rhs.data[i];
}
return * this ;
}
BigInteger & BigInteger::add( const BigInteger & rhs)
{
int i,nLen;
nLen = rhs.len > len ? rhs.len : len;
for (i = 0 ; i < nLen ; i ++ )
{
data[i] = data[i] + rhs.data[i];
if (data[i] > MAXN)
{
data[i + 1 ] ++ ;
data[i] = data[i] - MAXN - 1 ;
}
}
if (data[nLen] != 0 )
{
len = nLen + 1 ;
}
else
{
len = nLen;
}
return * this ;
}
BigInteger & BigInteger::sub( const BigInteger & rhs)
{
int i,j,nLen;
if (len > rhs.len)
{
for (i = 0 ; i < nLen ; i ++ )
{
if (data[i] < rhs.data[i])
{
j = i + 1 ;
while (data[j] == 0 ) j ++ ;
data[j] -- ;
-- j;
while (j > i)
{
data[j] += MAXN;
-- j;
}
data[i] = data[i] + MAXN + 1 - rhs.data[i];
}
else
{
data[i] -= rhs.data[i];
}
}
len = nLen;
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
else if (len == rhs.len)
{
for (i = 0 ; i < len ; i ++ )
{
data[i] -= rhs.data[i];
}
while (data[len - 1 ] == 0 && len > 1 )
{
-- len;
}
}
return * this ;
}
BigInteger BigInteger:: operator + ( const BigInteger & n) const
{
BigInteger a = * this ;
a.add(n);
return a;
}
BigInteger BigInteger:: operator - ( const BigInteger & T) const
{
BigInteger b = * this ;
b.sub(T);
return b;
}
BigInteger BigInteger:: operator * ( const BigInteger & rhs) const
{
BigInteger result;
int i,j,up;
int temp,temp1;
for (i = 0 ; i < len; i ++ )
{
up = 0 ;
for (j = 0 ; j < rhs.len; j ++ )
{
temp = data[i] * rhs.data[j] + result.data[i + j] + up;
if (temp > MAXN)
{
temp1 = temp - temp / (MAXN + 1 ) * (MAXN + 1 );
up = temp / (MAXN + 1 );
result.data[i + j] = temp1;
}
else
{
up = 0 ;
result.data[i + j] = temp;
}
}
if (up != 0 )
{
result.data[i + j] = up;
}
}
result.len = i + j;
while (result.data[result.len - 1 ] == 0 && result.len > 1 ) result.len -- ;
return result;
}
BigInteger BigInteger:: operator / ( const int & b) const
{
BigInteger ret;
int i,down = 0 ;
for (i = len - 1 ; i >= 0 ; i -- )
{
ret.data[i] = (data[i] + down * (MAXN + 1 )) / b;
down = data[i] + down * (MAXN + 1 ) - ret.data[i] * b;
}
ret.len = len;
while (ret.data[ret.len - 1 ] == 0 ) ret.len -- ;
return ret;
}
void BigInteger::print()
{
int i;
cout << data[len - 1 ];
for (i = len - 2 ; i >= 0 ; i -- )
{
cout.width(GROUP_LEN);
cout.fill( ' 0 ' );
cout << data[i];
}
cout << endl;
}
int main()
{
clock_t start, finish;
double duration;
int i,n;
BigInteger result,num;
scanf( " %d " , & n);
start = clock();
result = BigInteger( 1 );
for (i = 2 ;i <= n; ++ i)
{
num = BigInteger(i);
result = result * num;
}
result.print();
finish = clock();
duration = ( double )(finish - start) / CLOCKS_PER_SEC;
printf( " %f seconds/n " , duration );
return 0 ;
}
下面给出测试结果,
我的机器配置:酷睿双核2
.
0G
,
内存3G
,
计算10000的阶乘,我的机器用时3 . 312秒,在HDU的服务器上,10000的阶乘用时不到900毫秒。
计算12345的阶乘,我的机器用时5.078秒。
计算20000的阶乘,我的机器用时13.656秒。
计算10000的阶乘,我的机器用时3 . 312秒,在HDU的服务器上,10000的阶乘用时不到900毫秒。
计算12345的阶乘,我的机器用时5.078秒。
计算20000的阶乘,我的机器用时13.656秒。
用C/C++确实是会快些的,HDU的这道题目对Java程序的时限是5秒内完成1万的阶乘,但c/c++的时限是1秒,由此可以看出。
大家也可以试试在HDU的服务器上提交下你的代码,看看能否在1秒内通过。
此外,还有2个常见的N!题目,就是N!的尾数0的个数和N!的非零末尾数,有兴趣的同学可以自己看看。