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
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:
- Build a length-$k$ vector $v$ where
$$v[r]=#{d\mid n : d\equiv r\pmod{k}}.$$
- Compute the $n$-fold cyclic convolution power of $v$.
- 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