Question
A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.
As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.
Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
Haskell
import Data.List (sort, group, union)
import Data.Array
pairwise :: (a -> a -> a) -> [a] -> [a]
:ys:t) = f xs ys : pairwise f t
pairwise f (xs= t
pairwise _ t
primes :: [Int]
= 2 : _Y ((3 :) . gaps 5 . _U . map (\p-> [p*p, p*p+2*p..]))
primes where
= g (_Y g) -- recursion, Y combinator
_Y g :xs):t) = x : (union xs . _U . pairwise union) t -- ~= nub.sort.concat
_U ((x@(x:xs)
gaps k s| k < x = k : gaps (k+2) s -- ~= [k,k+2..]\\s, when
| otherwise = gaps (k+2) xs -- k <= head s && null(s\\[k,k+2..])
factorize :: Int -> [Int]
= primeFactors n primes where
factorize n 1 _ = []
primeFactors = []
primeFactors _ [] :ps) | m < p * p = [m]
primeFactors m (p| r == 0 = p : primeFactors q (p:ps)
| otherwise = primeFactors m ps
where (q, r) = quotRem m p
primePowers :: Int -> [(Int, Int)]
= [(head x, length x) | x <- group $ factorize n]
primePowers n
divisors :: Int -> [Int]
= filter (<n) $ map product $ sequence
divisors n take (k+1) $ iterate (p*) 1 | (p, k) <- primePowers n]
[
upperBound :: Int
= 20161
upperBound
abundant :: Int -> Bool
= (sum . divisors) n > n
abundant n
abundantsArray :: Array Int Bool
= listArray (1, upperBound) $ map abundant [1..upperBound]
abundantsArray
abundants :: [Int]
= filter (abundantsArray !) [1..upperBound]
abundants
remainders :: Int -> [Int]
= map (x-) $ takeWhile (<= x `quot` 2) abundants
remainders x
sums :: [Int]
= filter (any (abundantsArray !) . remainders) [1..upperBound]
sums
main :: IO ()
= print $ sum [1..upperBound] - sum sums main
$ ghc -O2 -o abundant abundant.hs
$ time ./abundant
real 0m0.034s
user 0m0.034s
sys 0m0.000s
Python
#!/usr/bin/env python3
import math
from collections import defaultdict
from itertools import *
from functools import reduce
def factorize(n):
if n < 1:
raise ValueError('fact() argument should be >= 1')
if n == 1:
return [] # special case
= []
res # iterate over all even numbers first.
while n % 2 == 0:
2)
res.append(//= 2
n # try odd numbers up to sqrt(n)
= math.sqrt(n+1)
limit = 3
i while i <= limit:
if n % i == 0:
res.append(i)//= i
n = math.sqrt(n+i)
limit else:
+= 2
i if n != 1:
res.append(n)= sorted(res)
factors = defaultdict(int)
histogram for factor in factors:
+= 1
histogram[factor]
return list(histogram.items())
def divisors(n):
= factorize(n)
factors = len(factors)
nfactors = [0] * nfactors
f while True:
yield reduce(lambda x, y: x*y, [factors[x][0]**f[x] for x in range(nfactors)], 1)
= 0
i while True:
+= 1
f[i] if f[i] <= factors[i][1]:
break
= 0
f[i] += 1
i if i >= nfactors:
return
def proper_divisors(n):
return list(divisors(n))[:-1]
def classify(n):
= sum(proper_divisors(n))
total if total == n:
# perfect
return 0
elif total > n:
# abundant
return 1
else:
# deficient
return -1
def main():
= set(number for number in range(2, 30000) if classify(number) == 1)
abundant = sorted(set(sum(c) for c in combinations_with_replacement(abundant, 2)))
sums print((sum(number for number in range(1,30000) if number not in sums)))
if __name__ == "__main__":
main()
$ time python3 abundant.py
real 0m16.594s
user 0m16.593s
sys 0m0.000s
Ruby
#!/usr/bin/env ruby
require 'mathn'
class Integer
def divisors
return [1] if self == 1
= self.prime_division.transpose
primes, powers = powers.map{|i| (0..i).to_a}
exponents = exponents.shift.product(*exponents).map do |powers|
divisors .zip(powers).map{|prime, power| prime ** power}.inject(:*)
primesend
.take divisors.length - 1
divisorsend
def abundant?
self.divisors.reduce(:+) > self
end
end
= (1..28213).select { |n| n.abundant? }
abundants = 0
i = []
sums .each do |x|
abundants[i..abundants.length].each do |y|
abundants= x + y
sum << sum unless sum > 28213
sums end
+= 1
i end
.uniq!
sumsputs (1..28213).reject { |n| sums.include? n }.reduce(:+)
$ time ruby abundant.rb
real 0m4.263s
user 0m4.231s
sys 0m0.032s
Rust
fn sum_divisors(n: usize) -> usize {
let mut result = 0;
let max = 1 + (n as f64).sqrt() as usize;
for i in 2..max {
if n % i == 0 {
let x = n / i;
if x == i {
+= i;
result } else {
+= i + x;
result }
}
}
1 + result
}
fn main() {
let max = 28123;
let abundant: Vec<usize> = (2..max + 1).filter(|&n| sum_divisors(n) > n).collect();
let mut abundant_sums = vec![false; 2 * max + 1];
for i in 0..abundant.len() {
for j in i..abundant.len() {
+ abundant[j]] = true;
abundant_sums[abundant[i] }
}
let sum: usize = (1..max + 1).filter(|&i| !abundant_sums[i]).sum();
println!("{}", sum);
}
$ rustc -C target-cpu=native -C opt-level=3 -o abundant abundant.rs
$ time ./abundant
real 0m0.030s
user 0m0.030s
sys 0m0.000s