题目: 对任意输入的正整数N,编写C程序求N!的尾部连续0的个数,并指出计算复杂度。如:18!=6402373705728000,尾部连续0的个数是3。 (不用考虑数值超出计算机整数界限的问题)
先考虑一种简单的情况, x * y 的尾部有几个0?
一个简单的方法就是先求出z=x*y的值, 再去查探z尾部有多少个0.
但是如果x * y的值很大, 导致z溢出呢?
把x分解为(x1 * x2 *x3 * x4 … xn), y分解为(y1 * y2 * y3 * y4 * …ym), 我们假设对x,y分解得比较恰当, 使得xi后面的数和yj后面的数怎样相乘都不会产生0, 而 xi前面的数和 yj前面的数都找到一对数使得其积为10.
比如, x = 35, y =8, 则可以分解为x =(5 * 7), y = (2 * 2 * 2), x1*y1 = 10, 而他们后面的数无论怎样相乘都不会得出有0结尾的数.
于是, 整个x * y尾部0的个数就是 xi前面的数和 yj前面的数的配对数, 在上例中为1对.
可以证明, 在所有素数中, 只有2*5的尾数为0, 其它无论怎样相乘都不会得出结尾为0的数.
所以, 该 求x * y 的尾部0的个数可以这样解: 把x, y分解质因数, 再求这些质因数中2和5配对的个数, 即为尾部0的个数.
对于n!进行质因数分解时, 2的个数必定比5的个数多,因为
5^1=5; 5^2=25; 5^3=125…
2^1=2; 2^2=4; 2^3=8 …
要使得a!中的5的个数比b!中2的个数多时, a必须要比b大很多.
所以, 其实我们只需要算出n!中质因数5的个数即可得出尾部0的个数了, 求n * (n – 1) * (n – 2) … * 1中含有5的个数方法如下:
设含有5的个数为k, 则
k = n/5 + n/25 + n / 125 … + n / 5i ( i = log5 (n))
可知k为一等比数列, 可得k = (n/5)(1-(1/5)i )/(1-1/5)
故输入n, 可以通过公式直接得到结果k.