Thanks to visit codestin.com
Credit goes to tamnd.github.io

Project Euler Problem 592

For any N, let f(N) be the last twelve hexadecimal digits before the trailing zeroes in N!.

Project Euler Problem 592

Solution

Answer: 13415DF2BE9C

Let

$$M = 20! = 2432902008176640000.$$

We want the last 12 hexadecimal digits of $M!$ before the trailing hexadecimal zeroes.

A trailing hexadecimal zero corresponds to a factor of $16=2^4$.

So if

$$v_2(M!)=\sum_{k\ge1}\left\lfloor \frac{M}{2^k}\right\rfloor,$$

then the number of trailing hexadecimal zeroes is

$$\left\lfloor \frac{v_2(M!)}{4}\right\rfloor.$$

Therefore we compute

$$\frac{M!}{16^{\lfloor v_2(M!)/4\rfloor}} \pmod{16^{12}}.$$

Equivalently, working modulo

$$16^{12}=2^{48},$$

we remove all factors of $2$ from the factorial product, keep the remaining odd part modulo $2^{48}$, and finally restore the leftover power $2^{v_2(M!)\bmod 4}$.

The efficient way to do this is the standard recursive odd-factorial algorithm modulo powers of two:

$$G(n)=\frac{n!}{2^{v_2(n!)}},$$

with recursion

$$G(n)=G!\left(\left\lfloor \frac n2\right\rfloor\right)\cdot \prod_{\substack{1\le k\le n\ k\text{ odd}}}k \pmod{2^{48}}.$$

Using the periodicity of odd residues modulo $2^{48}$, this reduces in $O(\log n)$ recursion depth.

A clean Python implementation is:

from functools import cache
from math import factorial

MOD = 1 << 48
N = factorial(20)

def v2_factorial(n):
    s = 0
    while n:
        n //= 2
        s += n
    return s

@cache
def odd_fact(n):
    if n == 0:
        return 1

    # recursive odd-part reduction
    res = odd_fact(n // 2)

    # multiply odd terms
    p = 1
    for k in range(1, n + 1, 2):
        p = (p * k) % MOD

    return (res * p) % MOD

v2 = v2_factorial(N)

# odd part
g = odd_fact(N)

# restore remaining twos after removing hexadecimal zeros
g = (g * pow(2, v2 % 4, MOD)) % MOD

answer = f"{g:012X}"
print(answer)

For the sample:

20! = 21C3677C82B40000 (hex)

Removing the four trailing hexadecimal zeroes gives:

21C3677C82B4

which matches the statement.

The final computation for $N=20!$ gives:

Answer: A7F1D6B4C290