Problem 167: Investigating Ulam Sequences

View on Project Euler

Project Euler Problem 167 Solution

EulerSolve provides an optimized solution for Project Euler Problem 167, Investigating Ulam Sequences, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary An Ulam sequence \(U(a,b)\) starts with \(a\) and \(b\). Every later term is the smallest integer larger than the previous term that can be written in exactly one way as a sum of two distinct earlier terms. In this problem we must evaluate $$S(k)=\sum_{n=2}^{10} u_k\bigl(U(2,2n+1)\bigr),$$ so the nine relevant sequences are \(U(2,5),U(2,7),\dots,U(2,21)\). The target index is enormous in the original problem, so a term-by-term generator is useless. The solution works only because this particular family of Ulam sequences has a highly constrained structure. Mathematical Approach Fix one sequence \(U(2,v)\) with \(v=2n+1\) odd. The core idea is that the even terms become trivial, and once that happens the odd terms are governed by a linear recurrence over \(\mathbb{F}_2\). The special even term \(E=2(v+1)\) For the nine values \(v=5,7,\dots,21\), the implementation exploits a specific fact about \(U(2,v)\): after the initial term \(2\), there is exactly one further even term, namely $$E=2(v+1).$$ Beyond that point the new members are odd. This matters because every odd candidate \(x>E\) can only be formed as $$x=2+(x-2),\qquad x=E+(x-E).$$ Odd numbers cannot come from odd plus odd, and there are no other even Ulam terms available. Therefore an odd number \(x>E\) enters the sequence exactly when one of \(x-2\) and \(x-E\) is already present and the other is not....

Detailed mathematical approach

Problem Summary

For positive integers \(a\) and \(b\), the Ulam sequence \(U(a,b)\) starts with \(U(a,b)_1=a\) and \(U(a,b)_2=b\); for \(k\gt2\), the term \(U(a,b)_k\) is the smallest integer greater than \(U(a,b)_{k-1}\) that can be written in exactly one way as the sum of two distinct earlier terms. The example in the statement, \(U(1,2)\), begins \(1,2,3,4,6,8,11\); the number \(5\) is missing because \(5=1+4=2+3\) has two such representations, and so is \(7=1+6=3+4\). We must find

$$\sum_{n=2}^{10}U(2,2n+1)_k,\qquad k=10^{11},$$

the sum of the \(10^{11}\)-th terms of the nine sequences \(U(2,5),U(2,7),\dots,U(2,21)\). [1]

The whole solution in one sentence: writing \(v=2n+1\), the only even terms of \(U(2,v)\) are \(2\) and \(2v+2\), so an odd number \(x\gt2v+2\) is a term exactly when one of \(x-2\) and \(x-2v-2\) is a term and the other is not, a rule under which the pattern of odd terms repeats in blocks, and counting whole blocks leads straight to the \(10^{11}\)-th term.

Mathematical Approach

Throughout, \(v\) is one of the odd numbers \(5,7,\dots,21\), so \(v=2n+1\), and \(U_k\) is the \(k\)-th term of \(U(2,v)\). We write

$$g=v+1,\qquad E=2v+2=2g.$$

A representation of \(x\) is a way of writing \(x=a+b\) with terms \(a\lt b\). Since the terms increase, a number \(x\gt v\) is a term exactly when it has exactly one representation: if it has exactly one and lies between two consecutive terms, the definition picks it as the next term.

1. A first look at \(U(2,5)\)

Starting from \(2\) and \(5\), the numbers \(7=2+5\), \(9=2+7\) and \(11=2+9\) have one representation each, while \(6\), \(8\) and \(10\) have none; \(10=5+5\) does not count, because the two terms must be distinct. Next, \(12=5+7\) and \(13=2+11\) are terms, \(14=2+12=5+9\) is not, \(15=2+13\) is, the numbers \(16=5+11=7+9\), \(17=2+15=5+12\) and \(18=5+13=7+11\) are not, and \(19=7+12\) is. Continuing in this way gives

$$\begin{aligned}&2,5,7,9,11,12,13,15,\\&19,23,27,29,35,37,41,43,\dots\end{aligned}$$

After \(12\) no even term appears, and Section 6 proves that none ever does. The odd numbers show the mechanism: the sum of two odd terms is even, so an odd number needs an even summand, and \(17\) fails because both \(2+15\) and \(12+5\) are available.

2. How every \(U(2,v)\) begins

The numbers between \(2\) and \(v\) are skipped by the definition. As long as \(2\) is the only even term, an odd number \(x\gt v\) has at most the representation \(2+(x-2)\), so \(x\) is a term exactly when \(x-2\) is, and \(v,v+2,\dots,2v+1\) are terms. An even number cannot use the summand \(2\), which would need a second even term, so it is a sum of two distinct odd terms, at least \(v+(v+2)=E\). The number \(E\) has this single representation and is the next even term. The odd numbers \(x\) from \(2v+3\) to \(3v\) have the representation \(2+(x-2)\) and no other, because \(x-E\le v-2\) is not a term. The even numbers between them are not terms: \(2v+4=2+E=v+(v+4)\), and every other even \(w\lt3v\) is both \(v+(w-v)\) and \((v+2)+(w-v-2)\). So \(U(2,v)\) begins with \(2\), all odd numbers from \(v\) to \(3v\), and \(E\), which is the term \(U_{(v+7)/2}\). For \(v=5\) these are \(2,5,7,9,11,12,13,15\).

3. The rule for odd numbers

Suppose that \(2\) and \(E\) are the only even terms below an odd number \(x\gt E\). Every representation of \(x\) consists of an even and an odd term, so it is \(2+(x-2)\) or \(E+(x-E)\). Hence \(x\) is a term exactly when one of \(x-2\) and \(x-E\) is a term and the other is not. For \(v=5\): \(17\) is not a term, because \(15\) and \(5\) both are; \(19\) is, because \(17\) is not and \(7\) is; \(21=2+19=9+12\) is not.

Under the same assumption, take the odd numbers \(x\) from \(3v+2\) to \(5v+2\). Then \(x-E\) runs through \(v,v+2,\dots,3v\), which are all terms, so \(x\) is a term exactly when \(x-2\) is not. Since \(3v\) is a term, the terms in this stretch are every second odd number,

$$\begin{aligned}&3v+4,\ 3v+8,\ 3v+12,\\&\dots,\ 5v+2,\end{aligned}$$

which for \(v=5\) are \(19\), \(23\) and \(27\).

4. Bits and a shift register

We record the odd numbers by bits: \(b_t=1\) if \(2t+1\) is a term and \(b_t=0\) otherwise, for \(t\ge0\). The odd numbers \(x-2\) and \(x-E\) belong to the indices \(t-1\) and \(t-g\), so for \(t\ge g\), that is \(x\ge2v+3\), the rule of Section 3 reads

$$b_t=b_{t-1}\oplus b_{t-g}\qquad(t\ge g),$$

where \(\oplus\) is addition modulo \(2\), the exclusive or. By Section 2, the first \(g\) bits, for the odd numbers \(1,3,\dots,2v+1\), are \((v-1)/2\) zeros followed by \((v+3)/2\) ones. For \(v=5\) they are \((0,0,1,1,1,1)\), and then

$$\begin{aligned}b_6&=b_5\oplus b_0=1,\\ b_7&=b_6\oplus b_1=1,\\ b_8&=b_7\oplus b_2=0,\end{aligned}$$

so \(13\) and \(15\) are terms and \(17\) is not, as in Section 1. The window \((b_{t-g+1},\dots,b_t)\) of the last \(g\) bits is a linear feedback shift register: each step appends the exclusive or of its oldest and its newest bit and drops the oldest one. [5]

5. Every window contains a term

The rule can be run backwards, \(b_{t-g}=b_t\oplus b_{t-1}\), so each window determines the one before it as well as the one after it. If some window consisted of zeros only, the window one step earlier would consist of zeros too, and so on back to the first window, which contains ones. Hence, for as long as the rule holds, among any \(g\) consecutive odd numbers at least one is a term. In \(U(2,5)\) the longest run of odd numbers that are not terms has length \(5\), for example \(121,123,125,127,129\) between the terms \(119\) and \(131\).

6. There is no third even term

Schmerl and Spiegel proved in 1994 that for every odd \(v\ge5\) the only even terms of \(U(2,v)\) are \(2\) and \(E\), which settled Finch's conjecture that these sequences are regular. [2] [3] Kuca retraces their proof for a closely related sequence, in which the two summands need not be distinct: the analogues of Sections 3 and 5 describe the odd numbers below a supposed third even term, and a second representation of that term is sought. [4] For our nine values of \(v\), the following argument of this kind is complete. Suppose that \(w\) is the smallest even term other than \(2\) and \(E\), so that Sections 3 to 5 hold below \(w\). Even numbers up to \(10v+4\) are excluded by direct computation: the C++ checkpoints build the first \(2000\) terms of each sequence from the definition, which reach beyond \(7700\), and find no third even term among them. So \(w\ge10v+6\).

The \(g\) terms \(a=v,v+2,\dots,3v\) have the partners \(w-a\), which form the window \(F\) of the \(g\) odd numbers from \(w-3v\) to \(w-v\). All of these exceed \(3v\), so every partner that is a term gives its own representation of \(w\). By Section 5, \(F\) contains a term, and since \(w\) has only one representation, it contains exactly one, \(p=w-a\). Now apply the backward rule to the odd numbers \(x\) of \(F\): \(x-E\) is a term exactly when exactly one of \(x\) and \(x-2\) is a term.

  • If \(v\lt a\lt3v\), then \(p-2\) and \(p+2\) lie in \(F\) and are not terms, so \(p-E\) and \(p+2-E\) are terms. Their partners \(a+2v+2\) and \(a+2v\) are two consecutive odd numbers between \(3v+2\) and \(5v\), and by Section 3 one of them is a term.
  • If \(a=v\), then \(p=w-v\) is the top of \(F\), and \(p-E\) is a term as before. The bottom \(w-3v\) of \(F\) is not a term, but \(w-3v-2=p-E\) is, so \(w-5v-2\) is a term, and its partner \(5v+2\) is a term by Section 3.
  • If \(a=3v\), then \(p=w-3v\) is the bottom of \(F\). The numbers \(w-v\) and \(w-v-2\) are not terms, so \(w-3v-2\) is not a term either, and therefore \(p-E=w-5v-2\) is a term, again with the partner \(5v+2\).

In every case \(w\) has a second representation, by a term from \(3v+2\) to \(5v+2\) and a term from \(w-5v-2\) to \(w-3v-2\). Since \(w\ge10v+6\), these two summands are distinct and differ from \(a\) and \(p\), which contradicts the choice of \(w\). Hence, in all nine sequences, the even terms are exactly \(2\) and \(E\), and the rule of Sections 3 and 4 holds for every odd number beyond \(E\).

7. The register repeats from the start

By Section 5, every window is one of the \(2^g-1\) nonzero patterns of \(g\) bits, so some window must occur twice. Because each window also determines the previous one, the first window that recurs is the very first window: if windows \(i\) and \(j\) were equal with \(0\lt i\lt j\), then going back \(i\) steps from both would make the first window equal to window \(j-i\). So the bits are periodic from \(t=0\) on: there is a smallest \(L\ge1\) with \(b_{t+L}=b_t\) for all \(t\ge0\), and \(L\le2^g-1\). Running the register for \(v=5,7,\dots,21\) gives \(L=63\), \(63\), \(889\), \(3255\), \(11811\), \(255\), \(253921\), \(761763\) and \(4194303\), and the numbers \(P\) of ones in one period are \(32\), \(26\), \(444\), \(1628\), \(5906\), \(80\), \(126960\), \(380882\) and \(2097152\).

8. The period from a polynomial

The period has an algebraic description through a generating function, a power series whose coefficients are the bits, here computed modulo \(2\); a sequence that obeys a linear recurrence has a rational generating function whose denominator comes from the recurrence. [6] Put \(B(y)=\sum_{t\ge0}b_ty^t\) and \(b_s=0\) for \(s\lt0\). For \(t\ge g\), the coefficient of \(y^t\) in \((1+y+y^g)\,B(y)\) is \(b_t\oplus b_{t-1}\oplus b_{t-g}=0\); for \(t\lt g\) it is \(b_t\oplus b_{t-1}\), which equals \(1\) only at the first one, \(t=m\). Hence

$$\begin{aligned}B(y)&=\frac{y^{m}}{1+y+y^{g}},\\ m&=\frac{v-1}{2}.\end{aligned}$$

The coefficient of \(y^t\) in \((1+y^L)\,B(y)\) is \(b_t\oplus b_{t-L}\), so \(b_{t+L}=b_t\) holds for all \(t\ge0\) exactly when this product is a polynomial of degree below \(L\). That happens exactly when \(1+y+y^g\) divides \(1+y^L\): then the product \(y^m(1+y^L)/(1+y+y^g)\) has degree \(L+m-g\lt L\), and conversely \(1+y+y^g\), whose constant term is \(1\), can divide \(y^m(1+y^L)\) only by dividing \(1+y^L\). So \(L\) is the smallest exponent with \(1+y+y^g\) dividing \(1+y^L\), the order of the trinomial \(y^g+y+1\), and the nine values above are the terms of OEIS A046932 for \(g=6,8,\dots,22\). [7] For \(v=5\) and \(v=21\) the period is \(2^g-1\), the largest possible: these two registers run through all nonzero windows, that is, they have maximal length, which happens exactly when \(y^6+y+1\) and \(y^{22}+y+1\) are primitive. [5] Their number of ones follows at once: each bit \(b_t\) is the newest bit of the window that ends at \(t\), one period visits every nonzero window once, and \(2^{g-1}\) of these windows have newest bit \(1\), so \(P=2^{g-1}\), that is \(P=32\) and \(P=2097152\).

9. From bits to terms

By Section 2, \(U_1=2\), the next \((v+3)/2\) terms are \(v,v+2,\dots,2v+1\), and \(U_{(v+7)/2}=E\). Every later term is odd: for \(k\ge(v+9)/2\), the term \(U_k\) is the \((k-2)\)-th odd term, \(U_k=2t+1\) for the position \(t\) of the \((k-2)\)-th one among the bits. Every block of \(L\) consecutive bits contains \(P\) ones, so the \((r+P)\)-th one lies \(L\) places after the \(r\)-th, and

$$U_{k+P}=U_k+2L\qquad\Bigl(k\ge\frac{v+9}{2}\Bigr).$$

So the differences of consecutive terms repeat with period \(P\), and the terms grow by \(2L\) over each repetition. No shorter period exists: if the differences repeated after \(Q\) terms with growth \(2D\), then \(b_{t+D}=b_t\) would hold for all large \(t\), hence for all \(t\), because the bits are periodic from the start; so \(D\) would be a multiple of the smallest period \(L\), and \(Q\) a multiple of \(P\). The numbers \(P\) and \(2L\) are known as the period and the fundamental difference of \(U(2,v)\). [8] This is an instance of Finch's theorem that an Ulam sequence with only finitely many even terms has eventually periodic differences. [3] For \(v=5\) the relation reads \(U_{k+32}=U_k+126\) for \(k\ge7\). It fails for \(k=6\), where \(U_6=12\) is the even term and \(U_{38}-U_6=125\).

10. Worked example: \(U(2,5)_{1000}\)

For \(v=5\) we have \(L=63\), \(P=32\) and \(E=U_6\). The index \(1000\) lies beyond \(6\), so we need the \(998\)-th odd term. The first window contains the first four odd terms \(5,7,9,11\), and the remaining \(994=31\cdot32+2\) ones consist of \(31\) full periods and the second one of the next period. A period that starts at \(t=6\) begins with \(b_6=b_7=1\), the terms \(13\) and \(15\), so the position is \(t=5+31\cdot63+2=1960\), and

$$U_{1000}=2\cdot1960+1=3921.$$

Section 9 gives the same value as \(U_8+31\cdot126=15+3906\), and a brute force from the definition confirms it.

How the Code Works

The C++ program [10] starts in main, where parse_arguments reads the options --k= (the index, \(10^{11}\) by default) and --skip-checkpoints; unless the latter is given, run_checkpoints runs first and the program stops with an error if a check fails, and then the result of solve_target_sum is printed. brute_ulam_terms(a, b, count) follows the definition: a hash map representation_count stores, for every sum of two distinct terms found so far, its number of representations capped at \(2\), the next term is the first candidate above the last term with count \(1\), and its sums with all earlier terms are then counted. brute_ulam_until_value stops at the first term that is at least a given value instead of after a given count.

The struct UlamOddCycle serves one \(v\). Its constructor sets gap to \(g\) and second_even to \(E\), generates the terms up to \(2v+3\) with brute_ulam_until_value and reads off the first window bits[0..gap-1] of Section 4; prefix_ones holds running counts of ones, and second_even_index is \(2+(v+3)/2\), the index of \(E\). The window is packed into the integer state, with \(b_0\) as its highest bit. Each step computes next_bit as the exclusive or of the oldest and the newest bit, \(b_{t-g}\oplus b_{t-1}\), appends it to bits and prefix_ones, and shifts it into state through lower_mask. The array seen, whose \(2^g\) entries start at \(-1\), stores the step at which each window first appeared, and the loop stops at the first repeated window. The code allows a preperiod, but by Section 7 the first window returns first, after exactly \(L\) steps, so cycle_t_start is \(g-1\), cycle_len is \(L\), ones_before_cycle is \((v+3)/2\) and ones_per_cycle is \(P\), and cycle_prefix_ones holds the running counts over one period \(t=g,\dots,g+L-1\).

kth_term(k) returns \(2\) for \(k=1\) and \(E\) for \(k=(v+7)/2\); otherwise it passes the rank \(r=k-1\) or \(r=k-2\) among the odd terms to odd_term_by_rank, as in Section 9. That function finds the first position \(t\) at which the count of ones reaches \(r\): inside the first window with std::lower_bound on prefix_ones, [9] and otherwise by writing \(R=r-(v+3)/2\) as \(qP+s\) with \(q=\lfloor(R-1)/P\rfloor\) complete periods, the variable full_cycles, and \(1\le s\le P\), the variable rem_inside_cycle; the \(-1\) makes \(R=P\) give \(s=P\), the last one of a period, instead of \(s=0\). One lower_bound on cycle_prefix_ones then locates the \(s\)-th one of a period. The result is \(2t+1\); Section 10 is this computation for \(v=5\). run_checkpoints compares the first seven terms of \(U(1,2)\) with the statement, and for each \(v\) it compares kth_term with brute_ulam_terms(2, v, 2000) at \(15\) indices from \(1\) to \(2000\), checks that \(2\) and \(E\) are the only even terms among these \(2000\), and checks the rule of Section 3 for every odd number from \(2v+3\) up to the \(2000\)-th term. solve_target_sum builds one UlamOddCycle for each \(v=5,7,\dots,21\) and adds the nine \(k\)-th terms.

In the Python program, solve contains brute_ulam and kth_term(v, k), which repeats the work of the constructor and replaces lower_bound by explicit binary searches over lo and hi. The Java program has bruteUlamUntilValue, whose HashMap caps the counts with merge, and kthTerm, which keeps the growing bits and prefix counts in ArrayList objects of boxed Byte and Long values. Neither runs checkpoints, and both fix \(k=10^{11}\). By Section 5, consecutive odd terms are at most \(2g\) apart, and the first one is \(v\lt2g\), so \(U_k\le2gk\); at \(k=10^{11}\) all terms, positions and counts therefore stay far inside the 64-bit types, std::uint64_t in C++ and long in Java, and Python's integers are unbounded anyway.

Complexity and Verification

For one value of \(v\), filling seen takes \(2^g\) steps and the walk of Section 7 takes \(L\le2^g-1\) steps of constant amortised cost, so the preprocessing needs \(O(2^g)\) time and memory; the walk has \(4194303\) steps for \(v=21\) and \(5226323\) over all nine sequences. The default C++ run builds every UlamOddCycle twice, once in the checkpoints and once for the sum. Memory is dominated by seen, with \(2^{22}=4194304\) entries for \(v=21\), and by the bit and prefix arrays of about \(L\) entries each. After the preprocessing, a query costs \(O(\log L)\) comparisons in the binary searches, and the arithmetic with full periods replaces the \(10^{11}\) steps of a direct generation. The checkpoints add about \(2\cdot10^6\) hash-map updates per sequence for their \(2000\) brute-force terms. On the machine used for this article, the C++ program with its checkpoints and the Java program finish in a fraction of a second, the Python program in about one second, and all three print the same value.

For this article we also ran checks that are not part of the published solutions:

  • For each sequence, a fast Fourier transform squared the indicator polynomial of the set formed by \(2\), \(E\) and the odd numbers \(2t+1\) with \(b_t=1\), up to \(2^{24}=16777216\); removing the sums \(a+a\) and halving gave the number of representations of every number in this range, with rounding errors below \(10^{-8}\). Every number from \(v+1\) to \(2^{24}\) is in this set exactly when it has exactly one representation, so by induction the set equals \(U(2,v)\) on this range, which holds \(2.6\) to \(4.3\) million terms; every even number from \(2v+6\) to \(2^{24}\) has at least two representations.
  • A test program that includes the C++ file unchanged finds kth_term equal to these terms for every \(k\) with \(U_k\le2^{24}\), in all nine sequences.
  • The C++ program with --k=, and copies of the Python and Java programs with the index replaced, agree with an independent evaluation of Section 9 at \(30\) indices between \(1\) and \(10^{12}\), among them \(10^{11}\). For \(k=1000\) the nine terms add up to \(38383\), as a brute force over the first \(1000\) terms of each sequence confirms.
  • The values of \(L\), \(P\) and \(2L\) found by the register agree with OEIS A046932, A100729 and A100730.

Footnotes and References

The references below supply the background facts used above. The proof of Section 6 for the nine sequences, the generating function of Section 8 and the operation counts are derived explicitly in this article.

  1. Project Euler 167 — Investigating Ulam Sequences. The official statement defines U(a, b), shows that U(1, 2) begins 1, 2, 3, 4, 6, 8, 11, and asks for the sum of the k-th terms of U(2, 2n + 1) for n = 2, …, 10 with k = 10¹¹.
  2. Wikipedia — Ulam number. It calls a sequence regular when its differences are eventually periodic and reports that Queneau observed this for (2, 7) and (2, 9), that Finch conjectured it for every (2, v) with odd v greater than 3 and that Schmerl and Spiegel proved it in 1994.
  3. MathWorld — Ulam Sequence. It states that Schmerl and Spiegel proved that the sequences (2, v) with odd v ≥ 5 have exactly two even terms (J. Combin. Theory Ser. A 66 (1994), 172–175), and that by Finch's work Ulam sequences with only finitely many even terms eventually have periodic differences.
  4. B. Kuca — Structures in Additive Sequences (arXiv:1804.09594). Section 3 mimics the proof of Schmerl and Spiegel for the sequences V(2, n), whose two summands need not be distinct: for a supposed third even term x, odd numbers below x obey the rule with the two even summands, every run of n consecutive odd numbers below x contains a term, and a second representation of x is sought.
  5. Wikipedia — Linear-feedback shift register. An all-zero register never changes, and a register runs through all 2ⁿ − 1 nonzero states, that is, has maximal length, if and only if its feedback polynomial is primitive over GF(2). By Wikipedia — Maximum length sequence, one period of such a sequence contains 2ⁿ⁻¹ ones and 2ⁿ⁻¹ − 1 zeros.
  6. Wikipedia — Linear recurrence with constant coefficients. The section on generating functions shows that such a sequence has a rational generating function, whose denominator is formed from the coefficients of the recurrence and whose numerator corrects the initial terms.
  7. OEIS A046932 — period of xⁿ + x + 1 over GF(2). The entry gives the smallest m > 0 such that xⁿ + x + 1 divides xᵐ + 1; for n = 6, 8, …, 22 its terms are 63, 63, 889, 3255, 11811, 255, 253921, 761763 and 4194303.
  8. OEIS A007300 lists U(2, 5), notes that among its first 300 terms only 2 and 12 are even, and gives a(n + 32) = a(n) + 126 for n > 6. OEIS A100729 and OEIS A100730 list the period and the fundamental difference of U(2, 2n + 1), from n = 2 on, the latter with the formula 2 · A046932(2n + 2).
  9. cppreference — std::lower_bound. On a sorted range it returns the first element that is not ordered before the given value, with at most log₂(N) + O(1) comparisons.
  10. C++ — Euler167.cpp. The linked immutable C++ revision contains UlamOddCycle, run_checkpoints and solve_target_sum. It is the implementation record for this article.

Problem 167 source code

C++

#include <algorithm>
#include <atomic>
#include <cstdint>
#include <exception>
#include <iostream>
#include <limits>
#include <stdexcept>
#include <string>
#include <thread>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace {

using u8 = std::uint8_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;

struct Options {
    u64 target_k = 100000000000ULL;
    bool run_checkpoints = true;
    unsigned requested_threads = 0U;
};

bool parse_unsigned_after_prefix(const std::string& arg,
                                 const std::string& prefix,
                                 unsigned& value) {
    if (arg.rfind(prefix, 0U) != 0U) {
        return false;
    }
    const std::string tail = arg.substr(prefix.size());
    if (tail.empty()) {
        return false;
    }

    u64 parsed = 0ULL;
    for (const char c : tail) {
        if (c < '0' || c > '9') {
            return false;
        }
        parsed = parsed * 10ULL + static_cast<u64>(c - '0');
        if (parsed > static_cast<u64>(std::numeric_limits<unsigned>::max())) {
            return false;
        }
    }

    value = static_cast<unsigned>(parsed);
    return true;
}

bool parse_u64_after_prefix(const std::string& arg,
                            const std::string& prefix,
                            u64& value) {
    if (arg.rfind(prefix, 0U) != 0U) {
        return false;
    }
    const std::string tail = arg.substr(prefix.size());
    if (tail.empty()) {
        return false;
    }

    u64 parsed = 0ULL;
    for (const char c : tail) {
        if (c < '0' || c > '9') {
            return false;
        }

        const u64 digit = static_cast<u64>(c - '0');
        if (parsed > (std::numeric_limits<u64>::max() - digit) / 10ULL) {
            throw std::overflow_error("--k overflow");
        }
        parsed = parsed * 10ULL + digit;
    }

    value = parsed;
    return true;
}

bool parse_arguments(const int argc, char** argv, Options& options) {
    for (int i = 1; i < argc; ++i) {
        const std::string arg(argv[i]);

        if (arg == "--skip-checkpoints") {
            options.run_checkpoints = false;
            continue;
        }
        if (parse_unsigned_after_prefix(arg, "--threads=", options.requested_threads)) {
            continue;
        }
        if (parse_u64_after_prefix(arg, "--k=", options.target_k)) {
            continue;
        }

        std::cerr << "Unknown argument: " << arg << '\n';
        return false;
    }

    return true;
}

unsigned pick_thread_count(const unsigned requested) {
    if (requested > 0U) {
        return requested;
    }

    unsigned hw = std::thread::hardware_concurrency();
    if (hw == 0U) {
        hw = 4U;
    }
    return hw;
}

std::vector<u64> brute_ulam_terms(const u64 a, const u64 b, const std::size_t count) {
    if (count == 0U) {
        return {};
    }
    if (count == 1U) {
        return {a};
    }

    std::vector<u64> seq;
    seq.reserve(count);
    seq.push_back(a);
    seq.push_back(b);

    std::unordered_map<u64, u8> representation_count;
    representation_count.reserve(count * count / 2 + 64U);
    representation_count[a + b] = 1U;

    u64 candidate = b + 1U;

    while (seq.size() < count) {
        while (true) {
            const auto it = representation_count.find(candidate);
            const u8 ways = (it == representation_count.end()) ? 0U : it->second;
            if (ways == 1U) {
                break;
            }
            ++candidate;
        }

        const u64 next = candidate;
        for (const u64 x : seq) {
            if (x == next) {
                continue;
            }
            const u64 sum = x + next;
            u8& ways = representation_count[sum];
            if (ways < 2U) {
                ++ways;
            }
        }

        seq.push_back(next);
        candidate = next + 1U;
    }

    return seq;
}

std::vector<u64> brute_ulam_until_value(const u64 a, const u64 b, const u64 min_last_value) {
    std::vector<u64> seq;
    seq.reserve(256U);
    seq.push_back(a);
    seq.push_back(b);

    std::unordered_map<u64, u8> representation_count;
    representation_count.reserve(32768U);
    representation_count[a + b] = 1U;

    u64 candidate = b + 1U;

    while (seq.back() < min_last_value) {
        while (true) {
            const auto it = representation_count.find(candidate);
            const u8 ways = (it == representation_count.end()) ? 0U : it->second;
            if (ways == 1U) {
                break;
            }
            ++candidate;
        }

        const u64 next = candidate;
        for (const u64 x : seq) {
            if (x == next) {
                continue;
            }
            const u64 sum = x + next;
            u8& ways = representation_count[sum];
            if (ways < 2U) {
                ++ways;
            }
        }

        seq.push_back(next);
        candidate = next + 1U;
    }

    return seq;
}

struct UlamOddCycle {
    int v = 0;
    int gap = 0;
    u64 second_even = 0ULL;

    std::vector<u8> bits;
    std::vector<u64> prefix_ones;

    u64 cycle_t_start = 0ULL;
    u64 cycle_t_end = 0ULL;
    u64 cycle_len = 0ULL;
    u64 ones_before_cycle = 0ULL;
    u64 ones_per_cycle = 0ULL;

    std::vector<u64> cycle_prefix_ones;

    u64 odd_less_than_second_even = 0ULL;
    u64 second_even_index = 0ULL;

    explicit UlamOddCycle(const int vv) : v(vv), gap(vv + 1), second_even(2ULL * static_cast<u64>(vv + 1)) {
        if (v < 1) {
            throw std::invalid_argument("v must be positive");
        }
        if (gap <= 0 || gap > 30) {
            throw std::runtime_error("Unexpected recurrence gap");
        }

        const u64 seed_limit = 2ULL * static_cast<u64>(gap) + 1ULL;
        const std::vector<u64> seed = brute_ulam_until_value(2ULL, static_cast<u64>(v), seed_limit);

        std::unordered_set<u64> members;
        members.reserve(seed.size() * 2U + 16U);
        for (const u64 x : seed) {
            members.insert(x);
        }

        bits.resize(static_cast<std::size_t>(gap), 0U);
        for (int t = 0; t < gap; ++t) {
            const u64 odd_value = 2ULL * static_cast<u64>(t) + 1ULL;
            bits[static_cast<std::size_t>(t)] = (members.find(odd_value) != members.end()) ? 1U : 0U;
        }

        prefix_ones.reserve(1U << 14U);
        prefix_ones.push_back(0ULL);
        for (const u8 bit : bits) {
            prefix_ones.push_back(prefix_ones.back() + static_cast<u64>(bit));
        }

        odd_less_than_second_even = prefix_ones[static_cast<std::size_t>(gap)];
        second_even_index = 2ULL + odd_less_than_second_even;

        const u32 state_count = 1U << static_cast<u32>(gap);
        std::vector<int> seen(state_count, -1);

        u32 state = 0U;
        for (int i = 0; i < gap; ++i) {
            state = (state << 1U) | static_cast<u32>(bits[static_cast<std::size_t>(i)]);
        }

        seen[state] = 0;

        const u32 lower_mask = (gap == 1) ? 0U : ((1U << static_cast<u32>(gap - 1)) - 1U);

        int step = 0;
        int cycle_step_start = -1;
        int cycle_step_end = -1;

        while (true) {
            const u32 oldest = (state >> static_cast<u32>(gap - 1)) & 1U;
            const u32 newest = state & 1U;
            const u32 next_bit = oldest ^ newest;

            bits.push_back(static_cast<u8>(next_bit));
            prefix_ones.push_back(prefix_ones.back() + static_cast<u64>(next_bit));

            state = ((state & lower_mask) << 1U) | next_bit;
            ++step;

            const int prev = seen[state];
            if (prev >= 0) {
                cycle_step_start = prev;
                cycle_step_end = step;
                break;
            }
            seen[state] = step;
        }

        cycle_t_start = static_cast<u64>(gap - 1 + cycle_step_start);
        cycle_t_end = static_cast<u64>(gap - 1 + cycle_step_end);
        cycle_len = cycle_t_end - cycle_t_start;

        ones_before_cycle = prefix_ones[static_cast<std::size_t>(cycle_t_start + 1ULL)];
        ones_per_cycle = prefix_ones[static_cast<std::size_t>(cycle_t_end + 1ULL)] - ones_before_cycle;

        if (cycle_len == 0ULL || ones_per_cycle == 0ULL) {
            throw std::runtime_error("Degenerate cycle detected");
        }

        cycle_prefix_ones.assign(static_cast<std::size_t>(cycle_len + 1ULL), 0ULL);
        for (u64 i = 0ULL; i < cycle_len; ++i) {
            const u64 t = cycle_t_start + 1ULL + i;
            cycle_prefix_ones[static_cast<std::size_t>(i + 1ULL)] =
                cycle_prefix_ones[static_cast<std::size_t>(i)] + static_cast<u64>(bits[static_cast<std::size_t>(t)]);
        }
    }

    u64 odd_term_by_rank(const u64 odd_rank) const {
        if (odd_rank == 0ULL) {
            throw std::invalid_argument("odd rank must be positive");
        }

        u64 t = 0ULL;

        if (odd_rank <= ones_before_cycle) {
            const auto begin_it = prefix_ones.begin() + 1;
            const auto end_it = prefix_ones.begin() + static_cast<std::ptrdiff_t>(cycle_t_start + 2ULL);
            const auto it = std::lower_bound(begin_it, end_it, odd_rank);
            t = static_cast<u64>(std::distance(prefix_ones.begin(), it)) - 1ULL;
        } else {
            const u64 rem = odd_rank - ones_before_cycle;
            const u64 full_cycles = (rem - 1ULL) / ones_per_cycle;
            const u64 rem_inside_cycle = rem - full_cycles * ones_per_cycle;

            const auto begin_it = cycle_prefix_ones.begin() + 1;
            const auto end_it = cycle_prefix_ones.end();
            const auto it = std::lower_bound(begin_it, end_it, rem_inside_cycle);
            const u64 d = static_cast<u64>(std::distance(cycle_prefix_ones.begin(), it));

            t = cycle_t_start + full_cycles * cycle_len + d;
        }

        return 2ULL * t + 1ULL;
    }

    u64 kth_term(const u64 k) const {
        if (k == 0ULL) {
            throw std::invalid_argument("k must be positive");
        }
        if (k == 1ULL) {
            return 2ULL;
        }

        if (k == second_even_index) {
            return second_even;
        }
        if (k < second_even_index) {
            return odd_term_by_rank(k - 1ULL);
        }
        return odd_term_by_rank(k - 2ULL);
    }
};

bool run_checkpoints() {
    {
        const std::vector<u64> sample = brute_ulam_terms(1ULL, 2ULL, 7U);
        const std::vector<u64> expected{1ULL, 2ULL, 3ULL, 4ULL, 6ULL, 8ULL, 11ULL};
        if (sample != expected) {
            std::cerr << "Checkpoint failed: U(1,2) sample mismatch\n";
            return false;
        }
    }

    const std::vector<u64> ks{1ULL, 2ULL, 3ULL, 4ULL, 5ULL, 6ULL, 10ULL, 20ULL,
                              50ULL, 100ULL, 250ULL, 500ULL, 1000ULL, 1500ULL, 2000ULL};

    for (int n = 2; n <= 10; ++n) {
        const int v = 2 * n + 1;
        const UlamOddCycle fast(v);
        const std::vector<u64> brute = brute_ulam_terms(2ULL, static_cast<u64>(v), 2000U);

        for (const u64 k : ks) {
            const u64 a = fast.kth_term(k);
            const u64 b = brute[static_cast<std::size_t>(k - 1ULL)];
            if (a != b) {
                std::cerr << "Checkpoint failed: mismatch at v=" << v << ", k=" << k
                          << ", fast=" << a << ", brute=" << b << '\n';
                return false;
            }
        }

        std::unordered_set<u64> members;
        members.reserve(brute.size() * 2U + 16U);
        for (const u64 x : brute) {
            members.insert(x);
        }

        const u64 second_even = 2ULL * static_cast<u64>(v + 1);
        for (const u64 x : brute) {
            if ((x & 1ULL) == 0ULL && x != 2ULL && x != second_even) {
                std::cerr << "Checkpoint failed: unexpected extra even term for v=" << v
                          << ", value=" << x << '\n';
                return false;
            }
        }

        for (u64 odd = second_even + 1ULL; odd <= brute.back(); odd += 2ULL) {
            const bool lhs = (members.find(odd) != members.end());
            const bool rhs = (members.find(odd - 2ULL) != members.end()) ^
                             (members.find(odd - second_even) != members.end());
            if (lhs != rhs) {
                std::cerr << "Checkpoint failed: odd recurrence mismatch at v=" << v
                          << ", odd=" << odd << '\n';
                return false;
            }
        }
    }

    return true;
}

u64 solve_target_sum(const u64 target_k, const unsigned requested_threads) {
    constexpr int first_n = 2;
    constexpr int last_n = 10;
    constexpr int task_count = last_n - first_n + 1;

    std::vector<u64> values(task_count, 0ULL);

    const unsigned thread_count =
        std::max(1U, std::min<unsigned>(pick_thread_count(requested_threads), task_count));

    if (thread_count == 1U) {
        for (int i = 0; i < task_count; ++i) {
            const int n = first_n + i;
            const int v = 2 * n + 1;
            const UlamOddCycle solver(v);
            values[static_cast<std::size_t>(i)] = solver.kth_term(target_k);
        }
    } else {
        std::atomic<int> next_task(0);
        std::vector<std::thread> workers;
        workers.reserve(thread_count);

        for (unsigned t = 0; t < thread_count; ++t) {
            workers.emplace_back([&]() {
                while (true) {
                    const int task = next_task.fetch_add(1, std::memory_order_relaxed);
                    if (task >= task_count) {
                        return;
                    }

                    const int n = first_n + task;
                    const int v = 2 * n + 1;
                    const UlamOddCycle solver(v);
                    values[static_cast<std::size_t>(task)] = solver.kth_term(target_k);
                }
            });
        }

        for (std::thread& worker : workers) {
            worker.join();
        }
    }

    u64 sum = 0ULL;
    for (const u64 value : values) {
        sum += value;
    }
    return sum;
}

} // namespace

int main(int argc, char** argv) {
    try {
        Options options;
        if (!parse_arguments(argc, argv, options)) {
            return 1;
        }

        if (options.run_checkpoints && !run_checkpoints()) {
            return 1;
        }

        const u64 answer = solve_target_sum(options.target_k, options.requested_threads);
        std::cout << answer << '\n';
    } catch (const std::exception& ex) {
        std::cerr << "Error: " << ex.what() << '\n';
        return 1;
    }

    return 0;
}

Python

def solve():
    target_k = 100000000000

    def brute_ulam(a, b, min_last):
        seq = [a, b]
        reps = {a + b: 1}
        cand = b + 1
        while seq[-1] < min_last:
            while True:
                w = reps.get(cand, 0)
                if w == 1: break
                cand += 1
            nxt = cand
            for x in seq:
                if x == nxt: continue
                s = x + nxt
                reps[s] = min(reps.get(s, 0) + 1, 2)
            seq.append(nxt)
            cand = nxt + 1
        return seq

    def kth_term(v, k):
        gap = v + 1
        second_even = 2 * (v + 1)
        seed_limit = 2 * gap + 1
        seed = brute_ulam(2, v, seed_limit)
        members = set(seed)

        bits = [1 if (2*t+1) in members else 0 for t in range(gap)]
        prefix = [0] * (gap + 1)
        for i in range(gap): prefix[i+1] = prefix[i] + bits[i]
        odd_lt_se = prefix[gap]
        se_idx = 2 + odd_lt_se

        state_count = 1 << gap
        seen = [-1] * state_count
        state = 0
        for i in range(gap): state = (state << 1) | bits[i]
        seen[state] = 0
        lower_mask = (1 << (gap-1)) - 1 if gap > 1 else 0
        bit_list = list(bits)
        po_list = list(prefix)
        step = 0
        while True:
            oldest = (state >> (gap-1)) & 1
            newest = state & 1
            nb = oldest ^ newest
            bit_list.append(nb)
            po_list.append(po_list[-1] + nb)
            state = ((state & lower_mask) << 1) | nb
            step += 1
            prev = seen[state]
            if prev >= 0:
                cycle_start = prev; cycle_end = step; break
            seen[state] = step

        cT_start = gap - 1 + cycle_start
        cT_end = gap - 1 + cycle_end
        cycle_len = cT_end - cT_start
        ones_before = po_list[cT_start + 1]
        ones_per_cycle = po_list[cT_end + 1] - ones_before
        cpf = [0] * (cycle_len + 1)
        for i in range(cycle_len):
            cpf[i+1] = cpf[i] + bit_list[cT_start + 1 + i]

        if k == 1: return 2
        if k == se_idx: return second_even
        odd_rank = k - 1 if k < se_idx else k - 2

        if odd_rank <= ones_before:
            lo, hi = 0, cT_start + 1
            while lo < hi:
                mid = (lo + hi) // 2
                if po_list[mid + 1] >= odd_rank: hi = mid
                else: lo = mid + 1
            return 2 * lo + 1
        else:
            rem = odd_rank - ones_before
            full_cycles = (rem - 1) // ones_per_cycle
            rem_inside = rem - full_cycles * ones_per_cycle
            lo, hi = 0, cycle_len
            while lo < hi:
                mid = (lo + hi) // 2
                if cpf[mid + 1] >= rem_inside: hi = mid
                else: lo = mid + 1
            t = cT_start + full_cycles * cycle_len + lo + 1
            return 2 * t + 1

    total = 0
    for n in range(2, 11):
        v = 2 * n + 1
        total += kth_term(v, target_k)
    return str(total)

if __name__ == '__main__':
    print(solve())

Java

import java.util.*;

public class Euler167 {
    static List<Long> bruteUlamUntilValue(long a, long b, long minLast) {
        List<Long> seq = new ArrayList<>();
        seq.add(a);
        seq.add(b);
        Map<Long, Integer> reps = new HashMap<>();
        reps.put(a + b, 1);
        long cand = b + 1;
        while (seq.get(seq.size() - 1) < minLast) {
            while (true) {
                int w = reps.getOrDefault(cand, 0);
                if (w == 1)
                    break;
                cand++;
            }
            long next = cand;
            for (long x : seq) {
                if (x == next)
                    continue;
                reps.merge(x + next, 1, (o, n) -> Math.min(o + n, 2));
            }
            seq.add(next);
            cand = next + 1;
        }
        return seq;
    }

    static long kthTerm(int v, long targetK) {
        int gap = v + 1;
        long secondEven = 2L * (v + 1);
        long seedLimit = 2L * gap + 1;
        List<Long> seed = bruteUlamUntilValue(2, v, seedLimit);
        Set<Long> members = new HashSet<>(seed);

        byte[] bits = new byte[gap];
        long[] prefixOnes = new long[gap + 1];
        for (int t = 0; t < gap; t++) {
            bits[t] = members.contains(2L * t + 1) ? (byte) 1 : 0;
            prefixOnes[t + 1] = prefixOnes[t] + bits[t];
        }
        long oddLessThanSecondEven = prefixOnes[gap];
        long secondEvenIndex = 2 + oddLessThanSecondEven;

        // Extend bits via XOR recurrence
        int stateCount = 1 << gap;
        int[] seen = new int[stateCount];
        Arrays.fill(seen, -1);
        int state = 0;
        for (int i = 0; i < gap; i++)
            state = (state << 1) | bits[i];
        seen[state] = 0;
        int lowerMask = gap == 1 ? 0 : (1 << (gap - 1)) - 1;
        List<Byte> bitList = new ArrayList<>();
        for (byte b : bits)
            bitList.add(b);
        List<Long> poList = new ArrayList<>();
        for (long p : prefixOnes)
            poList.add(p);
        int step = 0, cycleStart = -1, cycleEnd = -1;
        while (true) {
            int oldest = (state >> (gap - 1)) & 1, newest = state & 1, nextBit = oldest ^ newest;
            bitList.add((byte) nextBit);
            poList.add(poList.get(poList.size() - 1) + nextBit);
            state = ((state & lowerMask) << 1) | nextBit;
            step++;
            int prev = seen[state];
            if (prev >= 0) {
                cycleStart = prev;
                cycleEnd = step;
                break;
            }
            seen[state] = step;
        }
        long cycleTStart = gap - 1 + cycleStart, cycleTEnd = gap - 1 + cycleEnd;
        long cycleLen = cycleTEnd - cycleTStart;
        long onesBeforeCycle = poList.get((int) (cycleTStart + 1));
        long onesPerCycle = poList.get((int) (cycleTEnd + 1)) - onesBeforeCycle;
        long[] cyclePrefixOnes = new long[(int) (cycleLen + 1)];
        for (long i = 0; i < cycleLen; i++) {
            long t = cycleTStart + 1 + i;
            cyclePrefixOnes[(int) (i + 1)] = cyclePrefixOnes[(int) i] + bitList.get((int) t);
        }

        // kth term
        if (targetK == 1)
            return 2;
        if (targetK == secondEvenIndex)
            return secondEven;
        long oddRank = targetK < secondEvenIndex ? targetK - 1 : targetK - 2;
        // Find t such that prefix_ones[t+1] = oddRank
        long t;
        if (oddRank <= onesBeforeCycle) {
            int lo = 0, hi = (int) (cycleTStart + 1);
            while (lo < hi) {
                int mid = (lo + hi) / 2;
                if (poList.get(mid + 1) >= oddRank)
                    hi = mid;
                else
                    lo = mid + 1;
            }
            t = lo;
        } else {
            long rem = oddRank - onesBeforeCycle;
            long fullCycles = (rem - 1) / onesPerCycle;
            long remInside = rem - fullCycles * onesPerCycle;
            int lo = 0, hi = (int) cycleLen;
            while (lo < hi) {
                int mid = (lo + hi) / 2;
                if (cyclePrefixOnes[mid + 1] >= remInside)
                    hi = mid;
                else
                    lo = mid + 1;
            }
            t = cycleTStart + fullCycles * cycleLen + lo + 1;
        }
        return 2 * t + 1;
    }

    public static void main(String[] args) {
        long targetK = 100000000000L;
        long sum = 0;
        for (int n = 2; n <= 10; n++) {
            int v = 2 * n + 1;
            sum += kthTerm(v, targetK);
        }
        System.out.println(sum);
    }
}