求N!的最末位非零数

先看一个网友给的巧妙的解题思路:

解题过程:

  这题的解法很多,有很多解法现在还不是很理解,受网上朋友启发,觉得下面的算法是比较易懂的,现在归纳一下。 

  观察n!,可以发现在乘的过程中,对于任意 n > 1,n!的末尾第一个非0数字都是偶数。我们只需保留最后一位非零数。当要乘的数中含有因数5时,我们可以把所有的因数5都当作8来乘。这是因为:

...x2*5=...10(舍,因为非零末位肯定为偶数)或...60,最后一位非零数为6。而恰好2*8=16,末位为6。(x2表示02,12,22,32,...,92)

...x4*5=...70(舍)或...20,最后一位非零数为2。而恰好4*8=32,末位为2。

...x6*5=...30(舍)或...80,最后一位非零数为8。而恰好6*8=48,末位为8。

...x8*5=...90(舍)或...40,最后一位非零数为4。而恰好8*8=64,末位为4。

(对于n > 1时,最后一位不会出现 1, 7, 3, 9,而永远是2, 4, 6, 8的循环出现)

        因此,在迭代作乘法时,主要就是计算因子5的数量,同时最后非零位随着因子5的个数以4为循环节(即只需要取它的数量对4取模)。如2×8=6,6×8=8,8×8=4,64×8=2,2×8=6,此时出现循环,对于4,6,8情况也一下,那么对于不同情况下的因子5的数量,可以通过res[5][4] = {{1,1,1,1}, {2,6,8,4}, {4,2,6,8}, {6,8,4,2}, {8,4,2,6}}来得到。

  又最后的末尾 = 去掉5的倍数的数相乘所得的末尾(非零的)× 5 的倍数的数相乘的非零末位 = 最后的非0末尾 ,这两部分分别记为T1,T2

         观察1 * 2 * 3 * 4 * 6 * 7 * 8 * 9 * 1 * 2 * 3 * 4 * 6 * 7 * 8 * 9发现,阶乘最后非零位 1 2 6 4 4 8 4 6 6 2 6 4 4 8 4 6 显然出现了循环,这就是封闭性,故N!去掉5的倍数的最后非零数只要看整个数最后一位i即可,设N>=10,那么这个非零数 可由cvt[i] {6,6,2,6,4,4,4,8,4,6,     1,1,2,6,4,4,4,8,4,6得到,当N<10时,可由cvt[10+i]得到。所以T1可以很简单地得到。

         所有5的倍数为5,5X2,5X3,......,5Xi, 其中i=N/5。又5X5X2X5X3X......X5Xi = 5^iX(1X2X...Xi),前半部分5的因子个数为i,后半部分的又可以分为T1,T2两部分,这样递归下去直到最后i < 10为止,这时总的5的因子个数为(之前求出的5的因子的个数+i/5),5的因子的个数对4取模只要这个数的后两位对4取模即可,如123=(100+23)%4 = 23%4,最后的答案可以根据除因子5外其它的数的非零未位K(2,4,6,8)中的一个,和5的因子个数对4取模的值J,得结果为res[K/2][J]。以上都假设N>1,当N为0或时,那么同样可用res[0][0]作为结果。


下面给个具体例子再结合上面体会下:

以125为例,首先看到个位数为5,那么查表得1*2*3*4*6...124(其中不包含因子含5的项)末位非零数为4,然后125/5为25, 说明其中包含25个5因子,5*10*15*...*125=(5的25次方)*1*2*3*4*5*...*25。然后递归处理1*2*3*4*5...25。1*2*3*4*6*...*24(其中不包含因为含5的项)末位非零数为4,其中含5因子5个,然后求1*2*3*4*5,末位非零数为2,最终末位非零数为4*4*2*(5的30次方)=32*(5的30次方)=2*(5的30次方),5的30次方就是将2按照{2,6,8,4}循环节循环30%4次,即2次,最后结果为8。代码很好写,写个递归程序就行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值