549 Divisibility of Factorials

Problem 549

定义 ,给定一个整数 是最小的整数,使得 能够整除

举两个简单的例子,

定义

题目中给了一个当 的值用于测试:

首先要意识到,不可能把阶乘本身算出来,比如 1517,由质数 37 和 41 相乘得到,那么对应的 应该是 41,但是 41 的阶乘非常之大。

给定一个数 ,求满足题意的 ,因为这里肯定需要遍历所有的 这么大了,所以求 的函数的时间复杂度最好是常量时间, 也很快, 就太慢了,这都到 次了,复杂度已经高的吓人了,计算机无法短时间算出来了。所以我们下面的目标就是在合理的时间复杂搞定 这个函数:一定要控制在 以内。

首先,如果这个数 是质数,那么 肯定就是 本身。

对于一个非质数,一个可行的思路就是把 分解质因数,质因数出现的次数也是需要保留的,要不然 25 这个数,是 ,如果不保留质因数的次数,那么计算得到的 就成了 5 了,显然是不对的。然后再如何处理呢?

假设分解质因数结果是 想办法凑够 包含 1 个 又包含一个(如果 等于 2,这里还会多包含一个), 又包含一个 ,依次类推。再想办法凑够 。依此类推。共计 个结果,最大的那个数字就是我们要求的

以上想法计算 没啥问题。但是:分解质因数的函数离 还是差很远,所以导致短时间无法运算完毕。

如果我能过滤掉很多值不用去计算了,那么时间就能大大降低了。

首先 以内的质数占了 5.7% 的样子,所以这 5.7% 是不用计算的。

其次,考虑某个质数 ,乘以小于它的某个数 ,得到的这个值 也是p。写一个两层 for 循环就能得出这些 值,这占了大概 66.7%,这一下子就节省了大多数的时间。

再次,在上一条的基础上再进一步,某个质数 ,乘以两个小于它的数 ,得到的 值, 也是 。三层 for 循环能搞定,这大概占了 22.3%,又能节约挺多时间的了。这里可以做一个小的优化, 可以从 两者比较大的一方开始,因为如果 小于 ,那么这个数字肯定在上一步的时候就被标记了。

再再次,还能再排除 3.4% 的数据,这里也可以使用上面提到的优化思想。

最后,只剩约 1.9% 的数据需要按照之前说的逻辑进行判定了。

这次代码又丑又长,特别是中间的几个 for 循环嵌套。