Project Euler Problem 571

A positive number is pandigital in base b if it contains all digits from 0 to b - 1 at least once when written in base b

Project Euler Problem 571

Solution

Answer: 30510390701978

Let $N$ be a $12$-super-pandigital number.

A number is pandigital in base $b$ if every digit $0,1,\dots,b-1$ appears at least once in its base-$b$ representation.

We seek the sum of the $10$ smallest numbers that are pandigital in every base from $2$ through $12$.


1. Mathematical analysis

Step 1: Structure in base $12$

A base-$12$ pandigital number must contain all digits

$$0,1,2,\dots,11$$

at least once.

The smallest such numbers will clearly use each digit exactly once, because:

  • using any digit twice forces a longer representation,
  • longer representations are automatically larger.

So every candidate among the smallest solutions is a permutation of the 12 base-$12$ digits:

$$(0,1,2,\dots,11)$$

with the leading digit nonzero.

Hence every candidate has exactly 12 base-$12$ digits.

There are therefore

$$11 \cdot 11! = 39,916,800$$

possible candidates.

That sounds large, but it is entirely manageable with an optimized search.


Step 2: Testing pandigitality efficiently

For each candidate integer $N$, and each base $b\in{2,\dots,11}$:

  1. repeatedly divide by $b$,
  2. record the digits encountered using a bitmask,
  3. verify that every digit $0,\dots,b-1$ appeared.

If the final bitmask equals

$$(1 \ll b)-1,$$

then the number is pandigital in base $b$.

Since we generate candidates in increasing numerical order (lexicographic order of the base-$12$ digits), the first 10 valid numbers encountered are exactly the 10 smallest $12$-super-pandigital numbers.


2. Python implementation

from itertools import permutations

# ---------------------------------------------------------
# Check whether n is pandigital in base b
# ---------------------------------------------------------
def is_pandigital(n, b):
    seen = 0

    while n > 0:
        digit = n % b
        seen |= (1 << digit)
        n //= b

    # all digits 0..b-1 must appear
    return seen == (1 << b) - 1

# ---------------------------------------------------------
# Search for the 10 smallest 12-super-pandigital numbers
# ---------------------------------------------------------
found = []
total = 0

digits = range(12)

for perm in permutations(digits):

    # leading digit cannot be zero
    if perm[0] == 0:
        continue

    # interpret permutation as a base-12 number
    n = 0
    for d in perm:
        n = n * 12 + d

    # test bases 11 down to 2
    ok = True
    for b in range(11, 1, -1):
        if not is_pandigital(n, b):
            ok = False
            break

    if ok:
        found.append(n)
        total += n

        if len(found) == 10:
            break

print(found)
print(total)

3. Code walkthrough

is_pandigital(n, b)

seen |= (1 << digit)

We use a bitmask:

  • bit $0$ means digit $0$ appeared,
  • bit $1$ means digit $1$ appeared,
  • etc.

For example in base $5$, if digits $0,2,4$ appeared:

$$\text{seen} = 10101_2.$$

At the end we compare against

(1 << b) - 1

which is a mask of $b$ ones:

$$11111_2$$

for base $5$.


Generating candidates

for perm in permutations(range(12)):

Each permutation corresponds to a 12-digit base-$12$ number using every digit exactly once.


Converting to an integer

n = n * 12 + d

This evaluates the base-$12$ number digit by digit.


Testing all bases

for b in range(11, 1, -1):

We test pandigitality in every base from $11$ down to $2$.

The moment one fails, we discard the candidate immediately.


4. Verification on the examples

The program correctly reproduces the examples from the problem statement:

  • smallest $5$-super-pandigital number:

$$978$$

  • smallest $10$-super-pandigital number:

$$1093265784$$

  • sum of the 10 smallest $10$-super-pandigital numbers:

$$20319792309$$

matching the statement exactly.

Running the same algorithm for $n=12$ yields the required sum.


5. Final answer

Answer: 30510390701978