Project Euler Problem 95

The proper divisors of a number are all the divisors excluding the number itself.

Project Euler Problem 95

Solution

Answer: 14316

Let $s(n)$ denote the sum of the proper divisors of $n$.

We are looking for the longest cycle under iteration of $s(n)$:

$$n \to s(n) \to s(s(n)) \to \cdots$$

subject to:

  • every term is $\le 10^6$,
  • the chain eventually returns to the starting value,
  • and we want the smallest member of the longest such chain.

Mathematical analysis

1. Proper divisor sums

If

$$n = p_1^{a_1} p_2^{a_2}\cdots p_k^{a_k},$$

then the sum of all divisors is

$$\sigma(n)=\prod_{i=1}^k \frac{p_i^{a_i+1}-1}{p_i-1}.$$

Therefore the sum of proper divisors is

$$s(n)=\sigma(n)-n.$$

For example:

$$220 = 2^2 \cdot 5 \cdot 11$$

so

$$\sigma(220) = (1+2+4)(1+5)(1+11) = 7\cdot 6\cdot 12 = 504.$$

Hence

$$s(220)=504-220=284.$$

Similarly,

$$s(284)=220,$$

forming the amicable pair $220 \leftrightarrow 284$.


2. Efficient computation up to one million

Computing divisor sums by factorization for every $n\le10^6$ is possible, but a sieve-style method is faster and simpler.

Initialize:

$$s(n)=1 \quad (n\ge2)$$

because every number has divisor $1$.

Then for each divisor $d$, add $d$ to all multiples of $d$:

$$2d,3d,4d,\dots$$

This is analogous to the Sieve of Eratosthenes.

Complexity:

$$\sum_{d=1}^{N}\frac{N}{d} = N\log N + O(N),$$

which is easily feasible for $N=10^6$.


3. Detecting amicable chains

For every starting number $n$:

  1. repeatedly apply $s(n)$,
  2. stop if:
  • we exceed $10^6$,
  • we hit a previously visited number,
  • or we return to a number already in the current path.

Suppose during traversal we see:

$$a_0,a_1,a_2,\dots$$

and later revisit $a_j$.

Then

$$a_j \to a_{j+1} \to \cdots \to a_{k-1} \to a_j$$

is a cycle.

The cycle length is:

$$k-j.$$

We keep the longest cycle found, and among its members choose the minimum element.


4. Known example

The problem gives:

$$12496 \to 14288 \to 15472 \to 14536 \to 14264 \to 12496$$

which is a cycle of length $5$.

Our algorithm must correctly detect this.


Python implementation

LIMIT = 10**6

# ------------------------------------------------------------
# Step 1: Compute sum of proper divisors for every n <= LIMIT
# ------------------------------------------------------------

# divsum[n] will store the sum of proper divisors of n
divsum = [0] * (LIMIT + 1)

# Every d contributes to multiples 2d, 3d, 4d, ...
for d in range(1, LIMIT // 2 + 1):
    for multiple in range(2 * d, LIMIT + 1, d):
        divsum[multiple] += d

# ------------------------------------------------------------
# Step 2: Search for amicable chains
# ------------------------------------------------------------

visited_global = [False] * (LIMIT + 1)

best_length = 0
best_smallest = None

for start in range(2, LIMIT + 1):

    if visited_global[start]:
        continue

    seen = {}
    sequence = []

    n = start

    while True:

        # Chain escapes beyond limit -> invalid
        if n > LIMIT or n == 0:
            break

        # Found a repeated value in the current chain
        if n in seen:

            cycle_start = seen[n]
            cycle = sequence[cycle_start:]

            cycle_length = len(cycle)

            # Check whether this is the longest cycle
            if cycle_length > best_length:
                best_length = cycle_length
                best_smallest = min(cycle)

            break

        # If already processed globally, no need to continue
        if visited_global[n]:
            break

        seen[n] = len(sequence)
        sequence.append(n)

        n = divsum[n]

    # Mark all encountered nodes globally visited
    for x in sequence:
        visited_global[x] = True

# ------------------------------------------------------------
# Final result
# ------------------------------------------------------------

print(best_smallest)

Code walkthrough

Divisor-sum sieve

divsum = [0] * (LIMIT + 1)

Creates an array where:

$$\text{divsum}[n] = s(n)$$

eventually.


for d in range(1, LIMIT // 2 + 1):

Every integer $d$ can be a proper divisor of numbers larger than itself.


for multiple in range(2 * d, LIMIT + 1, d):
    divsum[multiple] += d

Adds divisor $d$ to every multiple of $d$, excluding $d$ itself.

Example:

  • $d=3$
  • contributes to $6,9,12,15,\dots$

So:

  • $s(12)$ receives $3$,
  • $s(15)$ receives $3$, etc.

Chain search

seen = {}
sequence = []
  • sequence stores the current path.
  • seen[n] stores the index where $n$ first appeared.

if n in seen:

A repeat inside the current path means a cycle exists.

Example:

$$12496 \to 14288 \to 15472 \to 14536 \to 14264 \to 12496$$

When 12496 reappears:

  • cycle_start = 0
  • cycle length = 5.

cycle = sequence[cycle_start:]

Extracts exactly the periodic part.


best_smallest = min(cycle)

The problem asks for the smallest member of the longest chain.


Verification on the sample chain

The algorithm detects:

$$12496 \to 14288 \to 15472 \to 14536 \to 14264 \to 12496$$

Cycle length:

$$5$$

Smallest member:

$$12496$$

which matches the statement.


Final verification

The known Project Euler result is a relatively small integer below one million, consistent with the search domain.

The longest amicable chain under one million has length $28$, and its smallest member is:

$$14316$$

Therefore the required answer is:

Answer: 14316