Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

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

All Problems

Problem 242: Odd Triplets

View on Project Euler

Project Euler Problem 242 Solution

EulerSolve provides an optimized solution for Project Euler Problem 242, Odd Triplets, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary For each pair \((n,k)\), let \(f(n,k)\) be the number of \(k\)-element subsets of \(\{1,2,\dots,n\}\) whose element sum is odd. An odd triplet is a triplet \((n,k,f(n,k))\) in which all three entries are odd. The quantity to evaluate is $A(N)=\#\{(n,k):1\le k\le n\le N,\ n,\ k,\ f(n,k)\text{ are all odd}\},$ and the implementations compute \(A(10^{12})\). The search space is far too large for direct enumeration, so the key is to understand only the parity of \(f(n,k)\), not its exact size. Mathematical Approach The derivation starts from a straightforward combinatorial count, turns that count into a parity statement over modulo 2 arithmetic, and then collapses the whole problem to a short prefix sum involving binary popcounts. Separating odd and even elements Let $o=\left\lceil\frac n2\right\rceil,\qquad e=\left\lfloor\frac n2\right\rfloor.$ Any \(k\)-subset of \(\{1,\dots,n\}\) has odd total exactly when it contains an odd number of odd elements. Therefore $f(n,k)=\sum_{\substack{j=0\\ j\text{ odd}}}^{k}\binom{o}{j}\binom{e}{k-j}.$ Because an odd triplet must have odd first and second coordinates, we only need \(n=2m+1\) and \(k=2r+1\)....

Detailed mathematical approach

Problem Summary

For each pair \((n,k)\), let \(f(n,k)\) be the number of \(k\)-element subsets of \(\{1,2,\dots,n\}\) whose element sum is odd. An odd triplet is a triplet \((n,k,f(n,k))\) in which all three entries are odd.

The quantity to evaluate is

$A(N)=\#\{(n,k):1\le k\le n\le N,\ n,\ k,\ f(n,k)\text{ are all odd}\},$

and the implementations compute \(A(10^{12})\). The search space is far too large for direct enumeration, so the key is to understand only the parity of \(f(n,k)\), not its exact size.

Mathematical Approach

The derivation starts from a straightforward combinatorial count, turns that count into a parity statement over modulo 2 arithmetic, and then collapses the whole problem to a short prefix sum involving binary popcounts.

Separating odd and even elements

Let

$o=\left\lceil\frac n2\right\rceil,\qquad e=\left\lfloor\frac n2\right\rfloor.$

Any \(k\)-subset of \(\{1,\dots,n\}\) has odd total exactly when it contains an odd number of odd elements. Therefore

$f(n,k)=\sum_{\substack{j=0\\ j\text{ odd}}}^{k}\binom{o}{j}\binom{e}{k-j}.$

Because an odd triplet must have odd first and second coordinates, we only need \(n=2m+1\) and \(k=2r+1\). Then \(o=m+1\) and \(e=m\), so

$f(2m+1,2r+1)=\sum_{\substack{j=0\\ j\text{ odd}}}^{2r+1}\binom{m+1}{j}\binom{m}{2r+1-j}.$

A parity-generating polynomial modulo 2

To study only parity, encode subset size by \(x\) and the parity of the subset sum by \(y\). Modulo 2, the relevant polynomial is

$P_n(x,y)=\prod_{i=1}^{n}\left(1+x\,y^{i\bmod 2}\right)=(1+x)^e(1+xy)^o,$

with the rule \(y^2=1\). The coefficient of \(x^k y\) is exactly \(f(n,k)\bmod 2\), because each chosen odd number contributes one factor of \(y\), and only the parity of the number of chosen odd elements matters.

For \(n=2m+1\), this becomes

$P_{2m+1}(x,y)=(1+x)^m(1+xy)^{m+1}.$

Now split into the parity of \(m\).

Why only \(n\equiv 1 \pmod 4\) can contribute

If \(m=2t+1\) is odd, then modulo 2 we can square factors:

$ (1+x)^{2t+1}=(1+x)(1+x^2)^t,\qquad (1+xy)^{2t+2}=(1+x^2)^{t+1}. $

Hence

$P_{4t+3}(x,y)=(1+x)(1+x^2)^{2t+1},$

which contains no \(y\)-term at all. Therefore every \(f(4t+3,2r+1)\) is even, so these values of \(n\) never produce odd triplets.

If instead \(m=2t\) is even, then

$ (1+x)^{2t}=(1+x^2)^t,\qquad (1+xy)^{2t+1}=(1+x^2)^t(1+xy), $

and therefore

$P_{4t+1}(x,y)=(1+x^2)^{2t}(1+xy).$

The coefficient of \(x^{2r+1}y\) is now the coefficient of \(x^{2r}\) in \((1+x^2)^{2t}\), namely

$f(4t+1,2r+1)\equiv \binom{2t}{r}\pmod 2.$

Equivalently, with \(m=(n-1)/2\),

$f(2m+1,2r+1)\text{ is odd}\iff m\text{ is even and }\binom{m}{r}\text{ is odd}.$

Lucas' theorem and the surviving values of \(k\)

Modulo 2, Lucas' theorem says

$\binom{u}{v}\equiv 1\pmod 2\iff (v\ \&\ \sim u)=0.$

In words: every 1-bit of \(v\) must sit under a 1-bit of \(u\). So if \(m=2t\), the admissible values of \(r\) are exactly the binary submasks of \(m\).

The number of such \(r\) is the number of odd entries in row \(m\) of Pascal's triangle:

$\#\{r:\binom{m}{r}\text{ odd}\}=2^{\operatorname{popcount}(m)}.$

Since \(m=2t\) only appends a trailing zero in binary, \(\operatorname{popcount}(m)=\operatorname{popcount}(t)\). Therefore each \(t\) contributes

$2^{\operatorname{popcount}(t)}$

odd triplets.

Collapsing the global count

The contributing values of \(n\) are exactly \(n=4t+1\). For a bound \(N\), the largest possible \(t\) is

$t_{\max}=\left\lfloor\frac{N-1}{4}\right\rfloor.$

So the entire Project Euler question reduces to

$A(N)=\sum_{t=0}^{t_{\max}}2^{\operatorname{popcount}(t)}.$

This is already a complete characterization of all odd triplets: every contributing \(n\) has the form \(4t+1\), and for that \(n\), the valid odd \(k\) are precisely those with \(k=2r+1\) where \(r\) is a binary submask of \(2t\).

Worked example: counting odd triplets up to \(N=10\)

Here

$t_{\max}=\left\lfloor\frac{10-1}{4}\right\rfloor=2.$

So we only inspect \(t=0,1,2\):

$ 2^{\operatorname{popcount}(0)}=1,\qquad 2^{\operatorname{popcount}(1)}=2,\qquad 2^{\operatorname{popcount}(2)}=2. $

The total is \(1+2+2=5\). Concretely, the contributing values are:

\(t=0 \Rightarrow n=1\), giving \(k=1\).

\(t=1 \Rightarrow n=5\), where row 2 of Pascal's triangle has odd entries at \(r=0,2\), giving \(k=1,5\).

\(t=2 \Rightarrow n=9\), where row 4 has odd entries at \(r=0,4\), giving \(k=1,9\).

That matches the small checkpoint used by the reference implementation: there are exactly 5 odd triplets with \(n\le 10\).

Evaluating the prefix sum in \(O(\log N)\)

Define

$S(T)=\sum_{t=0}^{T}2^{\operatorname{popcount}(t)}.$

The implementation scans the bits of \(T\) from most significant to least significant. Suppose the current bit is \(b\), this bit of \(T\) is 1, and there are already \(s\) ones in the higher prefix. If we set bit \(b\) to 0 and allow the lower \(b\) bits to vary freely, every lower pattern \(x\) contributes

$2^{s+\operatorname{popcount}(x)}.$

Summing over all \(x\in[0,2^b)\) gives

$2^s\sum_{x=0}^{2^b-1}2^{\operatorname{popcount}(x)}=2^s\cdot 3^b,$

because each lower bit independently contributes either a factor \(1\) or a factor \(2\), so the total product is \((1+2)^b=3^b\). After processing every set bit, one final term \(2^s\) accounts for \(T\) itself.

This transforms the whole problem into a constant-memory bit walk over at most 64 positions.

How the Code Works

Reducing the bound

The C++, Python, and Java implementations first replace the original upper bound \(N\) by

$T=\left\lfloor\frac{N-1}{4}\right\rfloor,$

because only \(n=4t+1\) can contribute. From that point on, the task is just to compute \(S(T)=\sum_{t=0}^{T}2^{\operatorname{popcount}(t)}\).

Prefix accumulation with powers of three

All three implementations precompute \(3^b\) for bit positions \(0\) through \(63\). They then scan the bits of \(T\) from high to low, keep track of how many 1-bits have already appeared in the prefix, and whenever a set bit is encountered they add the contribution \(2^s3^b\) for the branch in which that bit is turned off and the remaining suffix is arbitrary.

After the scan finishes, the remaining prefix itself contributes \(2^s\). That exactly reproduces the mathematical prefix-sum formula above, and it is why the final solver is extremely short in every language.

Validation strategy in the reference implementation

The C++ implementation also contains explicit correctness checks on small inputs. It verifies a direct sample value \(f(5,3)=4\), checks that the total number of odd triplets up to \(n=10\) is 5, compares the closed parity rule against direct combinatorial evaluation for all odd \(n\le 1001\), and tests the prefix-sum routine against a brute-force accumulation on a large range of small \(t\).

The Python and Java implementations keep only the compact production calculation, but they implement exactly the same mathematics.

Complexity Analysis

The actual solver performs one scan over the bit representation of \(T=\lfloor(N-1)/4\rfloor\). For a 64-bit bound this means at most 64 iterations, so the time complexity is \(O(\log N)\) and the memory usage is \(O(1)\).

The optional brute-force and parity-validation routines in the C++ version are only small safety checks; they are not part of the main Project Euler computation.

Footnotes and References

  1. Problem page: https://projecteuler.net/problem=242
  2. Lucas' theorem: Wikipedia - Lucas' theorem
  3. Binomial coefficient: Wikipedia - Binomial coefficient
  4. Pascal's triangle modulo 2 and the Sierpinski pattern: Wikipedia - Sierpinski triangle
  5. Generating functions: Wikipedia - Generating function

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

Previous: Problem 241 · All Project Euler solutions · Next: Problem 243

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! 🧮