Zadanie :
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Oto moja solucja :
$ints = []
1000.times{|x|
$ints << x if x%3==0 and !($ints.include?(x))
$ints << x if x%5==0 and !($ints.include?(x))
}
$sum = 0
$ints.each{|x|
$sum += x
}
puts $sum
$stdin.gets
Złożoność obliczeniowa powyższych rozwiązań to O(n).
Aby uzyskać stały czas O(1) należy skorzystać z faktu, że 3 + 6 + 9 + … + 999 to ciąg arytmetyczny. Analogicznie dla 5 + 10 + … + 995.
Sumę ciągu arytmetycznego można obliczyć za pomocą odpowiedniego wzoru.
Sumując powyższe dwa ciągi liczymy podwójnie liczby jednocześnie podzielne przez 3 i 5 (czyli podzielne przez 15).
Dlatego odejmujemy trzeci ciąg arytmetyczny 15 + 30 + 45 + … + 990.
[code=“ruby”]def arithmetic_sequence_sum(first, last, count)
(first + last) * 0.5 * count
end
def euler_1
res = 0
res += arithmetic_sequence_sum 3, 999, 999 / 3
res += arithmetic_sequence_sum 5, 995, 999 / 5
res -= arithmetic_sequence_sum 15, 990, 999 / 15
end
Nie tylko długość, ale i ilość ciągów można mnożyć:
def multiples(max,*nums)
(0..2**nums.size-1).inject do |sum,k|
ms = (0..nums.size-1).select{|i| k[i]==1}
m = ms.inject(1){|mul,x| mul.lcm nums[x]}
sum-(-1)**ms.size*m*(1+max/m)*(max/m)/2
end
end
puts multiples 999,3,5
puts multiples 999,3,5,7,11,13,17,19,21,23,29,31,37,41,43,47,49,51