每个非负整数都可以用它的素数分解来表示。因此,每个可以被2和20之间的所有数字整除的数字都可以表示
2**n2 * 3**n3 * 5**n5 * 7**n7 * 11**n11 * 13**n13 * 17**n17 * 19**n19
2、3、5、7、11、13、17 和 19 是 2 和 20 的值之间的质数,指数有待确定。
Ruby 提供了一个方法Prime::prime_division,它返回一个数字的素数分解。让我们计算2 和20 之间每个数字的素数分解:
(2..20).each { |n| puts "#{n}: #{Prime.prime_division(n)}" }
2: [[2, 1]]
3: [ [3, 1]]
4: [[2, 2]]
5: [ [5, 1]]
6: [[2, 1], [3, 1]]
7: [ [7, 1]]
8: [[2, 3]]
9: [ [3, 2]]
10: [[2, 1], [5, 1]]
11: [ [11, 1]]
12: [[2, 2], [3, 1]]
13: [ [13, 1]]
14: [[2, 1], [7, 1]]
15: [[3, 1], [5, 1]]
16: [[2, 4]]
17: [ [17, 1]]
18: [[2, 1], [3, 2]]
19: [ [19, 1]]
20: [[2, 2], [5, 1]]
12,例如等于2**2 * 3**1,表示为[2,2], [3,1]。每个二元组的形式为[p,e],其中p 是质数,e 是指数。
现在考虑2 和20 之间的每个素数。我们看到每个偶数都需要将2 提高到一个幂,其中最大值是4,对于16.that 这告诉我们每个数字n 可以被2 和@987654353 之间的每个数字整除@ 必须能被 2**4 整除。如果n能被2**4整除,当然也能被2**1、2**2和2**3整除,从而满足2和20之间所有其他偶数的要求。由此可见,上述表达式中的n2 必须至少为4。由于我们想要最小的素数乘积的幂,我们将n2 设置为4。
对于素数3。对于2 和20 之间的五个数字,可以被3 整除的指数为1、1、2、1 和2。所有能被2 和20 之间的所有数字整除的数字因此必须能被3**2 整除。因此,我们将n3 设置为2。
对剩余的每个素数 5、7、11、13、17 和 19 重复此操作,我们看到可被 2 和20等于
2**4 * 3**2 * 5**1 * 7**1 * 11**1 * 13**1 * 17**1 * 19**1
#=> 232792560
Ruby 有另一个方法,Prime::Prime.int_from_prime_division,它根据prime_division 返回的数组形式生成这个数字:
Prime.int_from_prime_division([[2,4], [3,2], [5,1], [7,1], [11,1], [13,1],
[17,1], [19,1]])
#=> 232792560
我们可以将其包含在以下计算中。
def smallest_divisible_by_2_to_n(n)
Prime.int_from_prime_division(
(2..n).each_with_object({}) do |n,h|
Prime.prime_division(n).each { |p,e| h[p] = [h[p].to_i, e].max }
end.to_a)
end
请注意,如果哈希 h 没有密钥 p,则 h[p] #=> nil。正是出于这个原因,我将h[p].to_i 写成nil.to_i #=> 0。见Nilclass#to_i。这种方法正好适用于这种情况。
smallest_divisible_by_2_to_n(10)
#=> 2520
smallest_divisible_by_2_to_n(20)
#=> 232792560
smallest_divisible_by_2_to_n(30)
#=> 2329089562800