【题目链接】
ybt 1173:阶乘和
注:一本通上这题,应该把
n
≤
50
n\le50
n≤50当做
n
≤
100
n\le100
n≤100来看
OpenJudge NOI 1.6 15:阶乘和
洛谷 P1009 [NOIP1998 普及组] 阶乘之和
【题目考点】
1.高精度
高精乘低精 高精加高精
【解题思路】
使用高精乘低精完成阶乘运算,使用高精加高精完成加和。
该题难点在于分析结果位数,为数字数组设一个合理的数组长度。(比如不知道结果位数,就设了数组长为10000,那你凭什么认为结果一定小于10000位?总得有点根据吧。)
求数字位数公式:假设数字x有n位,那么
n
=
⌊
l
g
x
⌋
+
1
n = \lfloor lgx \rfloor + 1
n=⌊lgx⌋+1
假设n=50,求
1
!
+
2
!
+
.
.
.
+
50
!
1!+2!+...+50!
1!+2!+...+50!的位数,我们可以不断将结果放大
1
!
+
2
!
+
.
.
.
+
50
!
≤
50
∗
50
!
≤
50
∗
5
0
50
=
5
0
51
1!+2!+...+50! \le 50*50! \le 50*50^{50}=50^{51}
1!+2!+...+50!≤50∗50!≤50∗5050=5051
求
5
0
51
50^{51}
5051的位数:
⌊
l
g
5
0
51
⌋
+
1
=
⌊
51
∗
l
g
50
⌋
+
1
≤
⌊
51
∗
l
g
100
⌋
+
1
=
103
\lfloor lg50^{51} \rfloor + 1 = \lfloor 51*lg50 \rfloor + 1 \le \lfloor 51*lg100 \rfloor + 1 = 103
⌊lg5051⌋+1=⌊51∗lg50⌋+1≤⌊51∗lg100⌋+1=103
将数字数组长度设为105就可以满足要求。
【注】一本通OJ上本题测试数据有误,需要将数字数组长度设为155才能过(我只试到155能过),否则有几个测试点会报“运行错误”。所以可以当这道题中给定的
n
≤
50
n\le50
n≤50当做
n
≤
100
n\le100
n≤100来看,这样推算出的数据位数就没有问题了。
【题解代码】
解法1:
本解法中,设置的高精度运算为 a*=b和a+=b。直接设可以完成a+b=c,a*b=c, a=b的高精度计算函数,也可以完成本题,具体做法略。
#include<bits/stdc++.h>
using namespace std;
#define N 155//一本通OJ上必须设为155才能过 洛谷、OpenJudge上设到105就能过
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++;
}
while(a[i] == 0 && i > 1)
i--;
a[0] = i;
}
void Add(int a[], int b[])//高精加高精 a += b
{
int c = 0, i;
for(i = 1; i <= a[0] || i <= b[0]; ++i)
{
a[i] += b[i] + c;
c = a[i] / 10;
a[i] %= 10;
}
if(c > 0)
a[i] = c;
while(a[i] == 0 && i > 1)
i--;
a[0] = i;
}
void shownum(int a[])
{
for(int i = a[0]; i >= 1; --i)
cout << a[i];
}
int main()
{
int a[N] = {1, 1}, s[N] = {1, 0}, n;//数字a初值为1 加和s初值为0
cin >> n;
for(int i = 1; i <= n; ++i)
{
Multiply(a, i);
Add(s, a);
}
shownum(s);
return 0;
}