【题目链接】
ybt 1172:求10000以内n的阶乘
OpenJudge NOI 1.6 14:求10000以内n的阶乘
【题目考点】
1. 高精度
考察:高精乘低精
高精度计算讲解
【解题思路】
先求结果最大的位数,也就是
10000
!
10000!
10000!的位数。
已知某正整数x的的位数为n,那么有:
n
=
⌊
l
g
x
⌋
+
1
n = \lfloor lgx \rfloor + 1
n=⌊lgx⌋+1(
l
g
x
lgx
lgx:以10为底x的对数)
位数为
⌊
l
g
10000
!
⌋
+
1
≤
⌊
l
g
1000
0
10000
⌋
+
1
=
⌊
10000
⋅
l
g
10000
⌋
+
1
=
⌊
10000
∗
4
⌋
+
1
=
40001
\lfloor lg10000! \rfloor + 1\le \lfloor lg10000^{10000} \rfloor + 1=\lfloor 10000\cdot lg10000 \rfloor + 1=\lfloor 10000*4 \rfloor + 1 = 40001
⌊lg10000!⌋+1≤⌊lg1000010000⌋+1=⌊10000⋅lg10000⌋+1=⌊10000∗4⌋+1=40001
数字数组长度取40005即可。
由于求10000的阶乘,每次乘的数字都是小于等于10000的数字,为低精度数字。阶乘的结果为高精度数字。所以应该使用高精乘低精。如果使用高精乘高精,算法复杂度会增大,可能会超时。
【题解代码】
解法1:使用函数与数组
#include <bits/stdc++.h>
using namespace std;
#define N 40005
void setLen(int a[], int i)
{
while(a[i] == 0 && i > 1)//去除多余的0
i--;
a[0] = i;
}
void Multiply(int a[], int b)//a *= b 高精乘低精
{
int c = 0, i;
for(i = 1; i <= a[0]; ++i)
{
a[i] = a[i]*b + c;
c = a[i] / 10;
a[i] %= 10;
}
while(c > 0)
{
a[i] = c % 10;
c /= 10;
i++;
}
setLen(a, i);
}
void toNum(char s[], int a[])
{
a[0] = strlen(s);
for(int i = 1; i <= a[0]; ++i)
a[i] = s[a[0] - i] - '0';
}
void showNum(int a[])
{
for(int i = a[0];i >= 1;--i)
cout << a[i];
}
int main()
{
int a[N] = {1, 1}, n;//高精度数字a初值为1
cin >> n;
for(int i = 1; i <= n; ++i)
Multiply(a, i);
showNum(a);
return 0;
}
解法2:类中重载运算符
#include <bits/stdc++.h>
using namespace std;
#define N 40005
struct HPN
{
int a[N];//数字数组
HPN()
{
memset(a, 0, sizeof(a));
}
HPN(char s[])
{
memset(a, 0, sizeof(a));
int len = strlen(s);
for(int i = 0; i < len; ++i)
a[len - i] = s[i] - '0';
a[0] = len;
}
void setLen(int i)
{
while(a[i] == 0 && i > 1)//去除多余的0
i--;
a[0] = i;
}
void operator *= (int b)//a *= b 高精乘低精
{
int c = 0, i;
for(i = 1; i <= a[0]; ++i)
{
a[i] = a[i]*b + c;
c = a[i] / 10;
a[i] %= 10;
}
while(c > 0)
{
a[i] = c % 10;
c /= 10;
i++;
}
setLen(i);
}
void show()
{
for(int i = a[0]; i >= 1; --i)
cout << a[i];
}
};
int main()
{
HPN a("1");//高精数字a初值为1
int n;
cin >> n;
for(int i = 1; i <= n; ++i)
a *= i;//高精乘低精
a.show();
return 0;
}