主题:[讨论]输入N,输出N!的最后一位非0的数字
此题唤起我童年的记忆...
当年我找规律....进行优化...最终没给出好结果。
我当时处理方式是利用C的位运算进行末几位的高精度计算,但是时间复杂度为O(N),当N很大时就没戏了。
昨天重新考虑了一下,得出一个可以证明的解法。时间复杂度为O(log(2, N)*log(5, N)),空间复杂度相同(递归)。
思路如下:
从1到N中:所有奇数末尾的3、5、7、9个数后抛弃。所有偶数各分离掉一个2,就得到一个新的自然数列,1到N/2。
找到了一个基本思想。可以统计出所有数的因子中,2,5的个数,还有3、5、7结尾的因子的个数。下面进一步完善。
显然1到N中,每10个数就有3、5、7、9各一个。至于最后的不到10各的零头也很容易可以根据零头的大小推断是否还有3、5、7、9。这样就是把N除以10的商和余数分离出来,进行4个判断就可以得到准确的3、5、7、9的个数。
2的个数就更简单了,直接为N/2.。也就是说整个过程不用从1到N依次分析,而是只要分析N这个数。
然后就考虑另一个情况:末尾是5的数只被计为一个5就被丢弃是不正确的,应该将其中的5分离出来然后再处理它的末位。于是我们每次做完以上操作后要进行另外一个递归,把N个数中5的倍数之外的数丢弃,然后各提取一个因子5,得到一个新序列1到N/5。然后统计其中的5、3、7、9的个数。方法同上,还是只分析N。
这样把2、5和3、7、9结尾因数的个数统计出来,5的个数抵消掉一部分2,最后就相当于若干2、3、7、9的相乘。我们找到的规律是:
个数 1 2 3 4 5
2 2 4 8 6 2
3 3 9 7 1 3
7 7 9 3 1 7
9 9 1 9 1 9
就是说这些它们幂的末尾数字都以4为循环周期,于是我们没必要用精度很高的空间去记录它们准确的个数,只要记录个数除以4的余数。
以上过程很难描述清楚,我还是建议大家结合自己的思考。
我自己的程序是C++的,有兴趣的可以参考一下,嫌麻烦没用高精度,谁有空改改或者译成Basic,谢了。因为该问题是在此版见到的,因此还是贴在这里讨论。
在此感谢“狱中肺炎”同学的四行秒杀1000!程序帮我验证结果。源程序位置:http://blog.programfan.com/article.asp?id=25193
当年我找规律....进行优化...最终没给出好结果。
我当时处理方式是利用C的位运算进行末几位的高精度计算,但是时间复杂度为O(N),当N很大时就没戏了。
昨天重新考虑了一下,得出一个可以证明的解法。时间复杂度为O(log(2, N)*log(5, N)),空间复杂度相同(递归)。
思路如下:
从1到N中:所有奇数末尾的3、5、7、9个数后抛弃。所有偶数各分离掉一个2,就得到一个新的自然数列,1到N/2。
找到了一个基本思想。可以统计出所有数的因子中,2,5的个数,还有3、5、7结尾的因子的个数。下面进一步完善。
显然1到N中,每10个数就有3、5、7、9各一个。至于最后的不到10各的零头也很容易可以根据零头的大小推断是否还有3、5、7、9。这样就是把N除以10的商和余数分离出来,进行4个判断就可以得到准确的3、5、7、9的个数。
2的个数就更简单了,直接为N/2.。也就是说整个过程不用从1到N依次分析,而是只要分析N这个数。
然后就考虑另一个情况:末尾是5的数只被计为一个5就被丢弃是不正确的,应该将其中的5分离出来然后再处理它的末位。于是我们每次做完以上操作后要进行另外一个递归,把N个数中5的倍数之外的数丢弃,然后各提取一个因子5,得到一个新序列1到N/5。然后统计其中的5、3、7、9的个数。方法同上,还是只分析N。
这样把2、5和3、7、9结尾因数的个数统计出来,5的个数抵消掉一部分2,最后就相当于若干2、3、7、9的相乘。我们找到的规律是:
个数 1 2 3 4 5
2 2 4 8 6 2
3 3 9 7 1 3
7 7 9 3 1 7
9 9 1 9 1 9
就是说这些它们幂的末尾数字都以4为循环周期,于是我们没必要用精度很高的空间去记录它们准确的个数,只要记录个数除以4的余数。
以上过程很难描述清楚,我还是建议大家结合自己的思考。
我自己的程序是C++的,有兴趣的可以参考一下,嫌麻烦没用高精度,谁有空改改或者译成Basic,谢了。因为该问题是在此版见到的,因此还是贴在这里讨论。
在此感谢“狱中肺炎”同学的四行秒杀1000!程序帮我验证结果。源程序位置:http://blog.programfan.com/article.asp?id=25193