Problem 618: Numbers with a Given Prime Factor Sum
View on Project EulerProject Euler Problem 618 Solution
EulerSolve provides an optimized solution for Project Euler Problem 618, Numbers with a Given Prime Factor Sum, with C++, Python, Java, and a step-by-step mathematical explanation.
Problem Summary For each nonnegative integer \(k\), let \(S(k)\) be the sum of all positive integers whose prime factors, counted with multiplicity, add up to \(k\). If $n=\prod_{p} p^{a_p},$ then \(n\) contributes to \(S(k)\) exactly when $\sum_{p} a_p p = k,$ where only finitely many exponents \(a_p\) are nonzero. Its contribution is the number itself, namely $n=\prod_{p} p^{a_p}.$ The task is to evaluate $\sum_{i=2}^{24} S(F_i)\pmod{10^9},$ with Fibonacci numbers defined by \(F_1=F_2=1\). The largest required argument is \(F_{24}=46368\), so one precomputation up to that bound is enough. Mathematical Approach The three implementations all exploit the same idea: instead of enumerating integers directly, they compute the coefficients of a generating function whose coefficient of \(x^k\) is exactly \(S(k)\). Step 1: Rewrite the Condition Using Prime Exponents Every positive integer has a unique prime factorization, so \(S(k)\) can be written as $S(k)=\sum_{\substack{a_p\ge 0\\ \sum_p a_p p = k}} \prod_p p^{a_p}.$ Each choice of exponents \((a_p)\) corresponds to one integer, and the weighted sum condition \(\sum_p a_p p = k\) says that each copy of the prime \(p\) contributes \(p\) units to the target total. The product \(\prod_p p^{a_p}\) is the value of the integer produced by that prime multiset. Step 2: Build the Generating Function Fix a prime \(p\)....
Detailed mathematical approach
Problem Summary
For each nonnegative integer \(k\), let \(S(k)\) be the sum of all positive integers whose prime factors, counted with multiplicity, add up to \(k\). If
$n=\prod_{p} p^{a_p},$
then \(n\) contributes to \(S(k)\) exactly when
$\sum_{p} a_p p = k,$
where only finitely many exponents \(a_p\) are nonzero. Its contribution is the number itself, namely
$n=\prod_{p} p^{a_p}.$
The task is to evaluate
$\sum_{i=2}^{24} S(F_i)\pmod{10^9},$
with Fibonacci numbers defined by \(F_1=F_2=1\). The largest required argument is \(F_{24}=46368\), so one precomputation up to that bound is enough.
Mathematical Approach
The three implementations all exploit the same idea: instead of enumerating integers directly, they compute the coefficients of a generating function whose coefficient of \(x^k\) is exactly \(S(k)\).
Step 1: Rewrite the Condition Using Prime Exponents
Every positive integer has a unique prime factorization, so \(S(k)\) can be written as
$S(k)=\sum_{\substack{a_p\ge 0\\ \sum_p a_p p = k}} \prod_p p^{a_p}.$
Each choice of exponents \((a_p)\) corresponds to one integer, and the weighted sum condition \(\sum_p a_p p = k\) says that each copy of the prime \(p\) contributes \(p\) units to the target total. The product \(\prod_p p^{a_p}\) is the value of the integer produced by that prime multiset.
Step 2: Build the Generating Function
Fix a prime \(p\). If it is used \(r\) times, then it contributes
$p^r x^{rp}=(p x^p)^r$
to the generating series: \(x^{rp}\) records that the prime-factor sum increases by \(rp\), and \(p^r\) records the multiplicative value contributed by those \(r\) copies of \(p\). Summing over all \(r\ge 0\) gives a geometric series:
$\sum_{r\ge 0}(p x^p)^r=\frac{1}{1-px^p}.$
Taking the product over all primes yields
$G(x)=\sum_{k\ge 0} S(k)x^k=\prod_{p}\frac{1}{1-px^p}.$
The constant term is \(1\), which corresponds to choosing no primes at all. This gives the convenient base value \(S(0)=1\); the requested values all have positive index, so this is only a bookkeeping device.
Step 3: Extract Coefficients with a One-Dimensional Recurrence
Assume we already know the coefficients of the partial product over some set of primes, and denote the current coefficient of \(x^t\) by \(A(t)\). When a new prime \(q\) is introduced, the series is multiplied by
$1+q x^q+q^2 x^{2q}+q^3 x^{3q}+\cdots.$
Therefore the updated coefficient is
$A_{\text{new}}(t)=\sum_{r\ge 0} q^r A_{\text{old}}(t-rq).$
This can be implemented in place by scanning \(t\) upward and applying
$A(t)\leftarrow A(t)+q\,A(t-q)\pmod{10^9}\qquad (t\ge q).$
That single formula is enough to reproduce the whole geometric series for the prime \(q\).
Step 4: Why the Increasing Sweep Is Correct
When the degrees are processed in increasing order, the entry at \(t-q\) has already been updated for the current prime. So it already includes the cases with zero, one, two, and more copies of \(q\). Multiplying by \(q\) and adding into degree \(t\) appends one extra copy of the same prime.
Because each prime is introduced only once, the method counts multisets of prime factors, not ordered sequences. That matches the number-theoretic definition exactly: \(2\cdot 3\cdot 3\) is one integer, not three different arrangements.
Step 5: Worked Example
To compute \(S(8)\), only primes up to \(8\) matter, so we may truncate the product at degree \(8\):
$G(x)=\frac{1}{(1-2x^2)(1-3x^3)(1-5x^5)(1-7x^7)}+O(x^9).$
The coefficient of \(x^8\) comes from exactly three choices:
$ (2x^2)^4,\qquad (2x^2)(3x^3)^2,\qquad (3x^3)(5x^5). $
These correspond to the integers
$16,\qquad 18,\qquad 15,$
so
$S(8)=16+18+15=49.$
Likewise, the degree \(5\) terms are \(5x^5\) and \((2x^2)(3x^3)\), giving
$S(5)=5+6=11.$
Both values agree with the checkpoints used by the implementation.
Step 6: Sum Only the Fibonacci Targets
Once all coefficients up to \(F_{24}\) have been computed, the problem is finished: we just read off the values at Fibonacci indices and add them:
$\text{Answer}=\sum_{i=2}^{24} S(F_i)\pmod{10^9}.$
No separate recomputation is needed for each \(F_i\). The same coefficient table serves every target value at once.
How the Code Works
The C++, Python, and Java implementations follow the same pipeline. First they generate the Fibonacci numbers up to \(F_{24}\), then they take \(46368\) as the global bound because that is the largest prime-factor sum that will ever be queried.
Next they generate every prime up to that bound with a sieve. After that they allocate one coefficient table of length \(46369\), set the degree-\(0\) entry to \(1\), and leave every other entry at \(0\).
For each prime, the implementation sweeps the table from low degree to high degree and applies the recurrence from the previous section modulo \(10^9\). When the sweep is complete, the entry at index \(k\) is the value of \(S(k)\) modulo \(10^9\).
Finally the implementation adds the entries at indices \(F_2,F_3,\dots,F_{24}\), reduces the total modulo \(10^9\), and prints the result as a 9-digit value with leading zeros if necessary.
Complexity Analysis
Let \(B=F_{24}=46368\). The sieve step takes \(O(B\log\log B)\) time and \(O(B)\) memory. The coefficient update then processes every prime \(q\le B\) across all degrees \(q,q+1,\dots,B\), so its running time is \(O(B\,\pi(B))\), where \(\pi(B)\) is the number of primes up to \(B\). The memory usage remains \(O(B)\) because only one sieve structure and one coefficient table are stored.
Footnotes and References
- Problem page: https://projecteuler.net/problem=618
- Fundamental theorem of arithmetic: Wikipedia - Fundamental theorem of arithmetic
- Generating function: Wikipedia - Generating function
- Geometric series: Wikipedia - Geometric series
- Sieve of Eratosthenes: Wikipedia - Sieve of Eratosthenes
- Fibonacci numbers: Wikipedia - Fibonacci number