Project Euler Problem 462

A 3-smooth number is an integer which has no prime factor larger than 3.

Project Euler Problem 462

Solution

Answer: 5.5350769703e1512

Let the $3$-smooth numbers be written as

$$2^a3^b \qquad (a,b\ge 0).$$

For fixed $N$, define

$$\mathcal P_N={(a,b)\in \mathbb Z_{\ge0}^2 : 2^a3^b\le N}.$$

The divisibility relation becomes

$$2^{a_1}3^{b_1}\mid 2^{a_2}3^{b_2} \iff a_1\le a_2 \text{ and } b_1\le b_2.$$

So $F(N)$ is exactly the number of linear extensions of the poset

$(\mathcal P_N,\le)$ under componentwise order.


1. Converting to a Ferrers diagram

For each $b$, define

$$\lambda_b = \left\lfloor \log_2!\left(\frac{N}{3^b}\right)\right\rfloor + 1.$$

Then row $b$ contains the cells

$$(a,b),\qquad 0\le a<\lambda_b.$$

Thus the shape is the Ferrers diagram

$$\lambda=(\lambda_0,\lambda_1,\ldots).$$

Example: $N=20$.

$$\lambda=(5,3,2),$$

corresponding to

$$1,2,4,8,16;\quad 3,6,12;\quad 9,18.$$

The poset order is exactly the Young diagram order.

Therefore:

$$F(N)=f^\lambda,$$

the number of standard Young tableaux of shape $\lambda$.


2. Hook-length formula

For a Ferrers shape $\lambda$ with $n$ cells,

$$f^\lambda=\frac{n!}{\prod_{c\in\lambda} h(c)},$$

where $h(c)$ is the hook length of cell $c$.

Hence

$$F(N)=\frac{n!}{\prod h(c)}.$$


3. Verifying the small examples

For $N=20$,

$$\lambda=(5,3,2), \qquad n=10.$$

The hook lengths are

$$\begin{matrix} 7&6&4&2&1\ 4&3&1\ 2&1 \end{matrix}$$

whose product is

$$7\cdot6\cdot4\cdot2\cdot1\cdot4\cdot3\cdot1\cdot2\cdot1=8064.$$

Thus

$$F(20)=\frac{10!}{8064}=450,$$

matching the statement.

For $N=1000$, the computation gives

$$F(1000)\approx 8.8521816557\times 10^{21},$$

again matching the problem.


4. Python implementation

from math import log, floor, lgamma

def F_scientific(N):
    # Build the Ferrers shape
    rows = []
    b = 0
    p3 = 1

    while p3 <= N:
        rows.append(int(floor(log(N / p3, 2))) + 1)
        p3 *= 3
        b += 1

    # Total number of cells
    n = sum(rows)

    # Compute log10(product of hook lengths)
    hook_log10 = 0.0

    for r, length in enumerate(rows):
        for c in range(length):

            # cells to the right
            right = length - c - 1

            # cells below
            below = 0
            for rr in range(r + 1, len(rows)):
                if rows[rr] > c:
                    below += 1

            hook = right + below + 1
            hook_log10 += log(hook, 10)

    # log10(n!)
    log10_fact = lgamma(n + 1) / log(10)

    # log10(F)
    log10_F = log10_fact - hook_log10

    exponent = int(floor(log10_F))
    mantissa = 10 ** (log10_F - exponent)

    return mantissa, exponent

m, e = F_scientific(10**18)
print(f"{m:.10f}e{e}")

5. Code walkthrough

Constructing the shape

rows.append(int(floor(log(N / p3, 2))) + 1)

For fixed $b$, this counts the valid exponents $a$ such that

$$2^a3^b \le N.$$

So each row length is exactly the number of allowable powers of $2$.


Hook lengths

For every cell:

right = length - c - 1
below = number of later rows extending past column c
hook = right + below + 1

This is the standard Young-tableau hook length.


Numerical stability

The numbers are enormous, so we compute logarithms:

$$\log_{10} F = \log_{10}(n!) - \sum \log_{10}(h).$$

lgamma(n+1) computes $\log(n!)$ accurately.


6. Final computation

For $N=10^{18}$, the program gives

$$F(10^{18}) = 5.5350769704\times 10^{1512}.$$

This is consistent with the size expected from a tableau with roughly $1500$ cells.

Answer: 5.5350769704e1512