Project-Euler-023

Problem

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.

Answer

1
4179871

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#!/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:
res.append(2)
n //= 2
# try odd numbers up to sqrt(n)
limit = math.sqrt(n+1)
i = 3
while i <= limit:
if n % i == 0:
res.append(i)
n //= i
limit = math.sqrt(n+i)
else:
i += 2
if n != 1:
res.append(n)
factors = sorted(res)
histogram = defaultdict(int)
for factor in factors:
histogram[factor] += 1

return list(histogram.items())

def divisors(n):
factors = factorize(n)
nfactors = len(factors)
f = [0] * nfactors
while True:
yield reduce(lambda x, y: x*y, [factors[x][0]**f[x] for x in range(nfactors)], 1)
i = 0
while True:
f[i] += 1
if f[i] <= factors[i][1]:
break
f[i] = 0
i += 1
if i >= nfactors:
return

def proper_divisors(n):
return list(divisors(n))[:-1]

def classify(n):
total = sum(proper_divisors(n))
if total == n:
# perfect
return 0
elif total > n:
# abundant
return 1
else:
# deficient
return -1

def main():
abundant = set(number for number in range(2, 30000) if classify(number) == 1)
sums = sorted(set(sum(c) for c in combinations_with_replacement(abundant, 2)))
print((sum(number for number in range(1,30000) if number not in sums)))

if __name__ == "__main__":
main()

Ruby

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env ruby
require 'mathn'

class Integer
def divisors
return [1] if self == 1
primes, powers = self.prime_division.transpose
exponents = powers.map{|i| (0..i).to_a}
divisors = exponents.shift.product(*exponents).map do |powers|
primes.zip(powers).map{|prime, power| prime ** power}.inject(:*)
end
divisors.take divisors.length - 1
end

def abundant?
self.divisors.reduce(:+) > self
end
end

abundants = (1..28213).select { |n| n.abundant? }
i = 0
sums = []
abundants.each do |x|
abundants[i..abundants.length].each do |y|
sum = x + y
sums << sum unless sum > 28213
end
i += 1
end
sums.uniq!
puts (1..28213).reject { |n| sums.include? n }.reduce(:+)

Haskell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import Data.List (sort, group, union)
import Data.Array

pairwise :: (a -> a -> a) -> [a] -> [a]
pairwise f (xs:ys:t) = f xs ys : pairwise f t
pairwise _ t = t

primes :: [Int]
primes = 2 : _Y ((3 :) . gaps 5 . _U . map (\p-> [p*p, p*p+2*p..]))
where
_Y g = g (_Y g) -- recursion, Y combinator
_U ((x:xs):t) = x : (union xs . _U . pairwise union) t -- ~= nub.sort.concat
gaps k s@(x:xs)
| 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]
factorize n = primeFactors n primes where
primeFactors 1 _ = []
primeFactors _ [] = []
primeFactors m (p:ps) | m < p * p = [m]
| r == 0 = p : primeFactors q (p:ps)
| otherwise = primeFactors m ps
where (q, r) = quotRem m p

primePowers :: Int -> [(Int, Int)]
primePowers n = [(head x, length x) | x <- group $ factorize n]

divisors :: Int -> [Int]
divisors n = filter (<n) $ map product $ sequence
[take (k+1) $ iterate (p*) 1 | (p, k) <- primePowers n]

upperBound :: Int
upperBound = 20161

abundant :: Int -> Bool
abundant n = (sum . divisors) n > n

abundantsArray :: Array Int Bool
abundantsArray = listArray (1, upperBound) $ map abundant [1..upperBound]

abundants :: [Int]
abundants = filter (abundantsArray !) [1..upperBound]

remainders :: Int -> [Int]
remainders x = map (x-) $ takeWhile (<= x `quot` 2) abundants

sums :: [Int]
sums = filter (any (abundantsArray !) . remainders) [1..upperBound]

main :: IO ()
main = print $ sum [1..upperBound] - sum sums

Clojure

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/usr/bin/env clojure
(defn divisors [n]
(filter #(= (rem n %) 0) (range 1 n)))

(defn perfect? [n]
(= (reduce + (divisors n)) n))

(defn abundant? [n]
(> (reduce + (divisors n)) n))

(defn deficient? [n]
(< (reduce + (divisors n)) n))

(println (filter abundant? (range 15000)))

Mathematica

1
2
3
4
5
6
7
8
9
10
11
lim = 28123;

isAbundant = Table[DivisorSigma[1, n] - n > n, {n, lim}];
abundants = Pick[Range[lim], isAbundant];
NotSumOfTwoAbundantsQ[n_] := Block[{i},
For[i = 1, i < Length[abundants] && abundants[[i]] < n, i++,
If[isAbundant[[n - abundants[[i]]]],
Return[False]]];
True]

Total[Select[Range[lim], NotSumOfTwoAbundantsQ]]

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public final class p023 implements EulerSolution {

public static void main(String[] args) {
System.out.println(new p023().run());
}


private static final int LIMIT = 28123;

private boolean[] isAbundant = new boolean[LIMIT + 1];

public String run() {
// Compute look-up table
for (int i = 1; i < isAbundant.length; i++)
isAbundant[i] = isAbundant(i);

int sum = 0;
for (int i = 1; i <= LIMIT; i++) {
if (!isSumOf2Abundants(i))
sum += i;
}
return Integer.toString(sum);
}


private boolean isSumOf2Abundants(int n) {
for (int i = 0; i <= n; i++) {
if (isAbundant[i] && isAbundant[n - i])
return true;
}
return false;
}


private static boolean isAbundant(int n) {
if (n < 1)
throw new IllegalArgumentException();

int sum = 1; // Sum of factors less than n
int end = Library.sqrt(n);
for (int i = 2; i <= end; i++) {
if (n % i == 0)
sum += i + n / i;
}
if (end * end == n)
sum -= end;
return sum > n;
}

}
文章作者: Monad Kai
文章链接: onlookerliu.github.io/2018/04/03/Project-Euler-023/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Code@浮生记
支付宝打赏
微信打赏