一道OJ的思考
这是一道OJ题,其中涉及到两个问题
1.如何求任何一个数的位数
2.如何求
n
!
n!
n!的末尾0的个数
(学过一点组合数学的都知道,有一个公式叫Stirling公式
1.如何求一个数的位数
有几种很简单的方法,例如循环之类的
但这里想说一种利用简单数学知识的方法
任意一个正整数a的位数
等于(int)log10(a) + 1;为什么呢?下面给大家推导一下:
对于任意一个给定的正整数a,
假设
1
0
x
−
1
<
=
a
<
1
0
x
10^{x-1} <= a < 10^x
10x−1<=a<10x,那么显然a的位数为x位,
又因为
lg
(
1
0
x
−
1
)
<
=
lg
(
a
)
<
lg
(
1
0
x
)
\lg(10^{x-1}) <= \lg(a) < \lg(10^x)
lg(10x−1)<=lg(a)<lg(10x)
即
x
−
1
<
=
l
o
g
10
(
a
)
<
x
x-1 <= log10(a) < x
x−1<=log10(a)<x
则
(
i
n
t
)
l
g
(
a
)
=
x
−
1
(int)lg(a) = x-1
(int)lg(a)=x−1,
即
(
i
n
t
)
l
g
(
a
)
+
1
=
x
(int)lg(a) + 1 = x
(int)lg(a)+1=x
即a的位数是
(
i
n
t
)
l
o
g
10
(
a
)
+
1
(int)log10(a)+1
(int)log10(a)+1
2. 如何求出N!的末尾零的个数
分析:一般类似的题目都会蕴含某种规律或简便方法的,阶乘末尾一个零表示一个进位,则相当于乘以10而10 是由2*5所得,在1~100当中,可以产生10的有:0 2 4 5 6 8 结尾的数字,显然2是足够的,因为4、6、8当中都含有因子2,所以都可看当是2,那么关键在于5的数量了那么该问题的实质是要求出1~100含有多少个5由特殊推广到一般的论证过程可得:
1、 每隔5个,会产生一个0,比如 5, 10 ,15,20.。。
2 、每隔 5×5 个会多产生出一个0,比如 25,50,75,100
3 、每隔 5×5×5 会多出一个0,比如125.
所以
100
!
100!
100!末尾有多少个零为:
100
/
5
+
100
/
25
=
20
+
4
=
24
100/5+100/25=20+4=24
100/5+100/25=20+4=24那么
1000
!
1000!
1000!末尾有多少个零呢?同理得:
1000
/
5
+
1000
/
25
+
1000
/
125
=
200
+
40
+
8
+
1
=
249
1000/5+1000/25+1000/125=200+40+8+1=249
1000/5+1000/25+1000/125=200+40+8+1=249
到此,问题解决了,但我们在学习过程中应当学会发散思维、举一反三
接着,请问
N
!
N!
N! 的末尾有多少个零呢??
其实 也是同理的
N
/
5
+
N
/
25
+
…
…
N/5+N/25+……
N/5+N/25+……
如计算 2009! 的末尾有多少个0:
2009
/
5
=
401
2009 / 5 = 401
2009/5=401
1~2009之间有 401 个数是 5 的倍数(余数省略).
401
/
5
=
80
401/5 = 80
401/5=80
1~2009 之间有 80 个数是 25 的倍数. 80 / 5 = 16 80/5 = 16 80/5=16
1~2009 之间有 16 个数是 125 的倍数. 16 / 5 = 3 16/5 = 3 16/5=3
1~2009 之间有 3个数是 625 的倍数. 3 / 5 = 0 3/5 = 0 3/5=0
1~2009 之间有 0 个数是 3125 的倍数.
所以, 2009! 的末尾有 401 + 80 + 16 + 3 = 500 401 + 80 + 16 + 3 = 500 401+80+16+3=500 个0.
3.Stirling公式
n
!
=
2
π
n
∗
(
n
e
)
n
n! = \sqrt{2 \pi n} * \left (\frac{n}{e}\right)^n
n!=2πn∗(en)n
或者更加准确地说是
l
i
m
n
→
∞
n
!
=
2
π
n
∗
(
n
e
)
n
lim_{n\to \infty} n! = \sqrt{2\pi n} * \left(\frac{n}{e}\right)^n
limn→∞n!=2πn∗(en)n
运用这个公式可以很好求出
n
!
n!
n!的位数,
~~(hahhh,我会用Markdown写公式啦,开心)~
4.AC代码如下
#include <cstdio>
#include <cmath>
#include <cstdlib>
#define eee exp(1)
#define pi acos(-1)
int main() {
int n;
while(~scanf("%d", &n)) {
long long ct1, ct2 = 0;
ct1 = (long long)(log10(2.0 * pi * n) * 0.5 + n * log10(n / eee)) + 1;
while(n){
ct2 += n / 5;
n /= 5;
}
printf("%lld ", ct1);
if(ct2) printf("%lld\n", ct2);
else printf("none\n");
}
return 0;
}