Project Euler Problem 511

Let Seq(n,k) be the number of positive-integer sequences ai{1 le i le n} of length n such that: - n is divisible by ai f

Project Euler Problem 511

Solution

Answer: 935247012

Let

$$D(n)={d : d\mid n}$$

be the set of positive divisors of $n$.

We must count sequences

$$(a_1,a_2,\dots,a_n),\qquad a_i\mid n$$

such that

$$n+a_1+\cdots+a_n\equiv 0\pmod{k}.$$

Equivalently,

$$a_1+\cdots+a_n\equiv -n\pmod{k}.$$

So the problem becomes:

Count length-$n$ sequences of divisors of $n$ whose sum is a prescribed residue modulo $k$.


1. Mathematical analysis

Define the polynomial in the ring

$$R=\mathbb Z[x]/(x^k-1)$$

by

$$P(x)=\sum_{d\mid n} x^{d}.$$

Each choice of a divisor contributes its residue modulo $k$.

When we multiply polynomials modulo $x^k-1$, exponents add modulo $k$. Therefore:

$$P(x)^n$$

encodes all length-$n$ sequences of divisors.

More precisely:

$$[x^r]P(x)^n$$

equals the number of sequences whose divisor sum is congruent to $r\pmod{k}$.

Hence

$$Seq(n,k)=[x^{-n\bmod k}]P(x)^n.$$

So the entire problem reduces to:

  1. Build a length-$k$ vector $v$ where

$$v[r]=#{d\mid n : d\equiv r\pmod{k}}.$$

  1. Compute the $n$-fold cyclic convolution power of $v$.
  2. Extract residue $(-n)\bmod k$.

Why cyclic convolution?

If vectors $A,B$ represent residue counts, then

$$(A*B)[t] = \sum_{i+j\equiv t\pmod{k}} A[i]B[j].$$

This is exactly multiplication modulo $x^k-1$.

So exponentiation by squaring works naturally.


2. Factorization of $n$

We need divisors of

$$n=1234567898765.$$

Factorization:

$$1234567898765 = 5\cdot 41\cdot 25343\cdot 237631.$$

All exponents are $1$, so there are

$$2^4=16$$

divisors total.


3. Efficient computation

A naive cyclic convolution costs $O(k^2)$, too slow for repeated squaring.

Instead we use:

  • Number Theoretic Transform (NTT)
  • Three NTT-friendly primes
  • Chinese Remainder Theorem (CRT)

This gives fast exact convolutions.

The vector length is only

$$k=4321,$$

so convolutions are very manageable.


4. Python implementation

from math import prod
from sympy import divisors

MOD = 10**9

# ------------------------------------------------------------
# NTT utilities
# ------------------------------------------------------------

PRIMES = [998244353, 1004535809, 469762049]
ROOTS  = [3, 3, 3]

CRT_MOD = prod(PRIMES)

Mi = [CRT_MOD // p for p in PRIMES]
INV = [pow(Mi[i], -1, PRIMES[i]) for i in range(3)]

def ntt(a, mod, primitive_root, invert=False):
    """
    Iterative in-place Number Theoretic Transform.
    """
    n = len(a)

    # Bit-reversal permutation
    j = 0
    for i in range(1, n):
        bit = n >> 1
        while j & bit:
            j ^= bit
            bit >>= 1
        j ^= bit

        if i < j:
            a[i], a[j] = a[j], a[i]

    length = 2

    while length <= n:

        wlen = pow(primitive_root, (mod - 1) // length, mod)

        if invert:
            wlen = pow(wlen, mod - 2, mod)

        half = length // 2

        for start in range(0, n, length):

            w = 1

            for i in range(start, start + half):

                u = a[i]
                v = a[i + half] * w % mod

                a[i] = (u + v) % mod
                a[i + half] = (u - v) % mod

                w = w * wlen % mod

        length *= 2

    if invert:
        inv_n = pow(n, mod - 2, mod)

        for i in range(n):
            a[i] = a[i] * inv_n % mod

# ------------------------------------------------------------
# Main solver
# ------------------------------------------------------------

def solve(n, k):

    # Build residue vector of divisors
    base = [0] * k

    for d in divisors(n):
        base[d % k] += 1

    # FFT size
    N = 1
    while N < 2 * k:
        N *= 2

    def cyclic_convolution(a, b):
        """
        Cyclic convolution modulo x^k - 1.
        """
        residue_results = []

        for mod, root in zip(PRIMES, ROOTS):

            fa = (a + [0] * (N - len(a))).copy()
            fb = (b + [0] * (N - len(b))).copy()

            fa = [x % mod for x in fa]
            fb = [x % mod for x in fb]

            ntt(fa, mod, root)
            ntt(fb, mod, root)

            for i in range(N):
                fa[i] = fa[i] * fb[i] % mod

            ntt(fa, mod, root, invert=True)

            # Fold coefficients modulo x^k - 1
            c = [0] * k

            for i, val in enumerate(fa[:2 * k - 1]):
                c[i % k] = (c[i % k] + val) % mod

            residue_results.append(c)

        # CRT reconstruction
        result = [0] * k

        for i in range(k):

            x = 0

            for j in range(3):
                x += residue_results[j][i] * Mi[j] * INV[j]

            result[i] = x % CRT_MOD % MOD

        return result

    # Fast exponentiation
    result = [0] * k
    result[0] = 1

    exponent = n

    while exponent:

        if exponent & 1:
            result = cyclic_convolution(result, base)

        base = cyclic_convolution(base, base)

        exponent >>= 1

    target = (-n) % k

    return result[target]

# ------------------------------------------------------------
# Verification on examples
# ------------------------------------------------------------

print(solve(3, 4))          # 4
print(solve(4, 11))         # 8
print(solve(1111, 24))      # 840643584

# Final problem
print(solve(1234567898765, 4321))

5. Code walkthrough

Building the divisor residue vector

for d in divisors(n):
    base[d % k] += 1

If a divisor has residue $r$, it contributes one way to obtain residue $r$.


Cyclic convolution

c[i % k] += val

This implements reduction modulo

$$x^k - 1,$$

because exponent $i$ wraps to $i \bmod k$.


Fast exponentiation

while exponent:

Computes

$$P(x)^n$$

using binary exponentiation.


Final extraction

target = (-n) % k

because we need

$$a_1+\cdots+a_n\equiv -n \pmod{k}.$$


6. Verification on given examples

The program reproduces:

$$Seq(3,4)=4$$

$$Seq(4,11)=8$$

and

$$Seq(1111,24)\equiv 840643584 \pmod{10^9},$$

matching the statement exactly.


7. Final computation

Running the program for

$$Seq(1234567898765,4321)$$

gives:

$$935247012.$$

Therefore:

Answer: 935247012