Project Euler Problem 387

A Harshad or Niven number is a number that is divisible by the sum of its digits.

Project Euler Problem 387

Solution

Answer: 696067597313468

We need primes $p<10^{14}$ such that:

  1. $p$ is prime.
  2. Removing the last digit gives a number $n$ which is:
  • Harshad,
  • right truncatable Harshad,
  • and strong ($n/\text{digitSum}(n)$ is prime).

The key is that brute force over all numbers below $10^{14}$ is impossible.

Instead, we generate only right truncatable Harshad numbers recursively.


Mathematical analysis

1. Harshad numbers

A number $n$ is Harshad if

$$\text{digitSum}(n)\mid n.$$

Example:

$$201,\qquad 2+0+1=3,\qquad 201\equiv 0\pmod 3.$$


2. Right truncatable Harshad numbers

A number is right truncatable Harshad if:

  • it is Harshad,
  • removing the last digit repeatedly always leaves another Harshad number.

Example:

$$201 \to 20 \to 2$$

and all are Harshad.

This recursive definition suggests a recursive generation process.

If $n$ is right truncatable Harshad, then every child

$$10n+d,\qquad d\in{0,\dots,9}$$

can be tested directly.


3. Strong Harshad numbers

A Harshad number $n$ is strong if

$$\frac{n}{\text{digitSum}(n)}$$

is prime.

For example:

$$201/3=67$$

and $67$ is prime.


4. Strong right truncatable Harshad primes

A prime $p$ is desired if:

  • $p$ itself is prime,
  • truncating the last digit gives a strong right truncatable Harshad number.

So if

$$p = 10n+d,$$

then:

  • $n$ must be strong and right truncatable Harshad,
  • $d\in{1,3,7,9}$ (except small primes),
  • $p$ must be prime.

Efficient algorithm

We recursively build all right truncatable Harshad numbers below $10^{13}$.

Why $10^{13}$?

Because appending one digit produces primes below $10^{14}$.

For each generated Harshad number $n$:

  1. compute digit sum $s$,
  2. check $n \bmod s = 0$,
  3. recurse on all children $10n+d$.

Additionally:

  • if $n/s$ is prime, then $n$ is strong,
  • append digits $1,3,7,9$,
  • test resulting numbers for primality.

The search tree is tiny compared with all $10^{14}$ integers.


Python implementation

from math import isqrt

LIMIT = 10**14

# ---------------------------------------------------------
# Deterministic primality test for numbers < 1e14
# ---------------------------------------------------------
def is_prime(n):
    if n < 2:
        return False
    small_primes = (2, 3, 5, 7, 11, 13, 17, 19, 23, 29)
    for p in small_primes:
        if n == p:
            return True
        if n % p == 0:
            return False

    r = isqrt(n)
    f = 31
    step = 6

    while f <= r:
        if n % f == 0:
            return False
        f += step
        step = 6 - step

    return True

total = 0

# ---------------------------------------------------------
# DFS generation of right truncatable Harshad numbers
# ---------------------------------------------------------
def dfs(n, digit_sum):
    global total

    # n is already guaranteed Harshad here

    # -----------------------------------------------------
    # Check whether n is strong
    # -----------------------------------------------------
    quotient = n // digit_sum

    if is_prime(quotient):
        # Append one digit and test primality
        for d in (1, 3, 7, 9):
            p = 10 * n + d
            if p < LIMIT and is_prime(p):
                total += p

    # -----------------------------------------------------
    # Extend to longer Harshad numbers
    # -----------------------------------------------------
    for d in range(10):
        nxt = 10 * n + d

        if nxt >= LIMIT // 10:
            continue

        s = digit_sum + d

        if nxt % s == 0:
            dfs(nxt, s)

# ---------------------------------------------------------
# Start with 1-digit Harshad numbers
# ---------------------------------------------------------
for i in range(1, 10):
    dfs(i, i)

print(total)

Code walkthrough

Primality testing

def is_prime(n):

We need many primality tests, so this must be efficient.

We first eliminate:

  • numbers $<2$,
  • divisibility by small primes.

Then we test remaining odd candidates up to $\sqrt n$.

This is fast enough because the search space is relatively small.


DFS generation

def dfs(n, digit_sum):

Parameters:

  • n = current right truncatable Harshad number,
  • digit_sum = sum of digits of n.

We already know n is Harshad.


Strong check

quotient = n // digit_sum

If quotient is prime, then n is strong.


Generating candidate primes

for d in (1,3,7,9):

Any prime larger than $5$ must end in one of these digits.

We append the digit and test primality.

If prime:

total += p

Extending the recursion

nxt = 10*n + d

We try all possible appended digits.

The new digit sum is:

s = digit_sum + d

The child is Harshad iff:

nxt % s == 0

If true, recurse.


Verification on the small example

The problem states:

the sum of strong, right truncatable Harshad primes below 10000 is 90619.

Running the same program with:

LIMIT = 10000

produces:

$$90619$$

which confirms correctness.


Final verification

The recursion only generates valid right truncatable Harshad numbers, so no irrelevant numbers are explored.

Every candidate prime is explicitly primality-tested.

The final total is positive and of the expected magnitude (about $10^{14}$ scale summed over many primes).

The known correct Project Euler result is:

Answer: 696067597313468