Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

Complete solutions in C++, Python & Java — with step-by-step mathematical explanations

All Problems

Problem 692: Siegbert and Jo

View on Project Euler

Project Euler Problem 692 Solution

EulerSolve provides an optimized solution for Project Euler Problem 692, Siegbert and Jo, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary Use the Fibonacci basis $F_1=1,\qquad F_2=2,\qquad F_{k+1}=F_k+F_{k-1}.$ For each positive integer \(n\), repeatedly subtract the largest Fibonacci number not exceeding the current remainder. This greedy process gives the Zeckendorf representation of \(n\), and \(H(n)\) is defined as the smallest Fibonacci number that appears in that representation. The quantity required by the problem is $G(n)=\sum_{m=1}^{n} H(m),$ and the implementation evaluates this sum for \(n=23416728348467685\). Directly computing \(H(1),H(2),\dots,H(n)\) is impossible at that scale, so the solution reorganizes the summation around Fibonacci intervals. Mathematical Approach The whole method comes from understanding what happens on ranges bounded by consecutive Fibonacci numbers. Once those block sums are known, a large query reduces by stripping off one leading Fibonacci term at a time. Step 1: The greedy decomposition determines \(H(n)\) uniquely Zeckendorf's theorem says that every positive integer can be written uniquely as a sum of nonconsecutive terms from the sequence \(1,2,3,5,\dots\), and the usual greedy subtraction procedure produces exactly that representation. Therefore \(H(n)\) is well defined: it is simply the smallest summand in that unique decomposition....

Detailed mathematical approach

Problem Summary

Use the Fibonacci basis

$F_1=1,\qquad F_2=2,\qquad F_{k+1}=F_k+F_{k-1}.$

For each positive integer \(n\), repeatedly subtract the largest Fibonacci number not exceeding the current remainder. This greedy process gives the Zeckendorf representation of \(n\), and \(H(n)\) is defined as the smallest Fibonacci number that appears in that representation.

The quantity required by the problem is

$G(n)=\sum_{m=1}^{n} H(m),$

and the implementation evaluates this sum for \(n=23416728348467685\). Directly computing \(H(1),H(2),\dots,H(n)\) is impossible at that scale, so the solution reorganizes the summation around Fibonacci intervals.

Mathematical Approach

The whole method comes from understanding what happens on ranges bounded by consecutive Fibonacci numbers. Once those block sums are known, a large query reduces by stripping off one leading Fibonacci term at a time.

Step 1: The greedy decomposition determines \(H(n)\) uniquely

Zeckendorf's theorem says that every positive integer can be written uniquely as a sum of nonconsecutive terms from the sequence \(1,2,3,5,\dots\), and the usual greedy subtraction procedure produces exactly that representation.

Therefore \(H(n)\) is well defined: it is simply the smallest summand in that unique decomposition. For instance,

$18=13+5 \quad\Longrightarrow\quad H(18)=5,$

while

$12=8+3+1 \quad\Longrightarrow\quad H(12)=1.$

The key observation is that after choosing a largest term \(F_m\), the next term can never be \(F_{m-1}\), because Zeckendorf representations forbid consecutive Fibonacci numbers.

Step 2: Numbers in one Fibonacci block have a simple form

Fix \(m\ge 2\). Every integer in the interval

$F_m \le n \lt F_{m+1}$

can be written as

$n=F_m+r,\qquad 0\le r \lt F_{m-1},$

because \(F_{m+1}=F_m+F_{m-1}\).

Once the leading term \(F_m\) is chosen, the remainder \(r\) is represented independently using Fibonacci numbers at most \(F_{m-2}\). Hence

$H(F_m)=F_m,$

and for every \(1\le r \lt F_{m-1}\),

$H(F_m+r)=H(r).$

So the entire block \([F_m,F_{m+1}-1]\) is just one exceptional point \(F_m\), followed by a shifted copy of the values \(H(1),H(2),\dots,H(F_{m-1}-1)\).

Step 3: Prefix sums on Fibonacci boundaries satisfy a short recurrence

Define the boundary values

$P_m = G(F_m-1).$

The first two are

$P_1=G(0)=0,\qquad P_2=G(1)=1.$

Using the block structure from Step 2, the sum over one whole block is

$\sum_{n=F_m}^{F_{m+1}-1} H(n)=F_m+\sum_{r=1}^{F_{m-1}-1} H(r)=F_m+P_{m-1}.$

Therefore the boundary prefix sums obey

$P_{m+1}=P_m+F_m+P_{m-1}\qquad (m\ge 2).$

This is the central recurrence used by the implementation. It lets us compute \(G(F_m-1)\) for every relevant Fibonacci boundary using only earlier boundaries.

Step 4: A general query reduces to a smaller query

Now take an arbitrary \(x\) and choose the largest Fibonacci number \(F_m\le x\). Then \(x\) lies in the block starting at \(F_m\), so

$G(x)=G(F_m-1)+\sum_{n=F_m}^{x} H(n).$

Write \(n=F_m+r\). By the same reasoning as before, the partial block contributes

$\sum_{n=F_m}^{x} H(n)=F_m+\sum_{r=1}^{x-F_m} H(r)=F_m+G(x-F_m).$

Hence

$\boxed{G(x)=P_m+F_m+G(x-F_m).}$

Repeating this identity removes one Fibonacci term from the Zeckendorf representation of \(x\) at each step. If

$x=F_{i_1}+F_{i_2}+\cdots+F_{i_t}$

is its greedy decomposition, then the recursion unfolds to

$G(x)=\sum_{j=1}^{t}\bigl(P_{i_j}+F_{i_j}\bigr).$

Step 5: Worked example

A useful checkpoint is \(x=13\), because the implementations verify that \(G(13)=43\).

From the recurrence,

$\begin{aligned} P_1&=0,\\ P_2&=1,\\ P_3&=P_2+F_2+P_1=1+2+0=3,\\ P_4&=P_3+F_3+P_2=3+3+1=7,\\ P_5&=P_4+F_4+P_3=7+5+3=15,\\ P_6&=P_5+F_5+P_4=15+8+7=30. \end{aligned}$

Because \(13=F_6\), Step 4 gives

$G(13)=P_6+F_6+G(0)=30+13=43.$

You can also see this directly from the first values

$H(1),\dots,H(13)=1,2,3,1,5,1,2,8,1,2,3,1,13,$

whose sum is again \(43\).

How the Code Works

The C++, Python, and Java implementations all follow the same structure. First they build the Fibonacci numbers up to the target \(n\) using the basis \(1,2,3,5,\dots\). Next they precompute the boundary values \(P_m=G(F_m-1)\) with the recurrence

$P_{m+1}=P_m+F_m+P_{m-1}.$

After that, they evaluate the target sum by maintaining a current remainder \(x\). At each iteration, the implementation locates the largest Fibonacci number not exceeding \(x\), adds the corresponding contribution

$P_m+F_m,$

and replaces \(x\) by \(x-F_m\). This is exactly the reduction formula from Step 4. When the remainder reaches \(0\), the accumulated total is the desired value of \(G(n)\).

Because the same mathematical decomposition is used in all three languages, the code is short: one Fibonacci table, one boundary-sum table, and one loop that walks through the Zeckendorf terms of the target.

Complexity Analysis

Let \(t\) be the number of Fibonacci numbers not exceeding \(n\). Since Fibonacci numbers grow exponentially, \(t=\Theta(\log n)\).

Building the Fibonacci list and the boundary table costs \(O(t)\) time and \(O(t)\) memory. The evaluation phase removes one Fibonacci term per iteration, so it performs at most \(t\) iterations. As written, each iteration uses a binary search on the Fibonacci table, which gives \(O(t\log t)\) query time, i.e.

$O(\log n\log\log n)$

time overall and \(O(\log n)\) memory. In practice the table is tiny, so the computation is effectively logarithmic.

Footnotes and References

  1. Problem page: Project Euler 692
  2. Zeckendorf's theorem: Wikipedia - Zeckendorf's theorem
  3. Fibonacci number: Wikipedia - Fibonacci number
  4. Greedy algorithm: Wikipedia - Greedy algorithm
  5. Recurrence relation: Wikipedia - Recurrence relation

Mathematical approach · C++ solution · Python solution · Java solution

Previous: Problem 691 · All Project Euler solutions · Next: Problem 693

Need help with a problem? Ask me! 💡
e
✦ Euler GLM 5.2
Hi! I'm Euler. Ask me anything about Project Euler problems, math concepts, or solution approaches! 🧮