Open Source · 7 Languages · 900+ Problems

Project Euler Solutions

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

All Problems

Problem 828: Numbers Challenge

View on Project Euler

Project Euler Problem 828 Solution

EulerSolve provides an optimized solution for Project Euler Problem 828, Numbers Challenge, with C++, Python, Java, and a step-by-step mathematical explanation.

Problem Summary Each challenge gives a target integer \(t\) and a short list \(a_1,\dots,a_n\). We may choose any nonempty subset of positions, use each chosen number exactly once, and combine them with binary operations. The implementations allow addition, multiplication, positive subtraction, and exact division, so every intermediate result remains a positive integer. For one challenge, the score is the smallest possible sum of the chosen numbers that can produce \(t\). If no legal expression reaches the target, the score is \(0\). The final answer is the weighted sum of the 200 challenge scores, with weights \(3^r\), taken modulo \(1005075251\). Mathematical Approach Write \([n]=\{1,\dots,n\}\). For every nonempty subset \(A\subseteq [n]\), let $\sigma(A)=\sum_{i\in A} a_i.$ The main task is to determine exactly which positive integers can be formed by expressions that use the positions in \(A\) and no others. Step 1: Interpret legal formulas as binary expression trees Any valid expression has a topmost operation whose left and right children are themselves valid expressions. Therefore the set of used positions splits into two disjoint nonempty parts \(B\) and \(C\) with $A=B\cup C,\qquad B\cap C=\varnothing,\qquad B\ne\varnothing,\qquad C\ne\varnothing.$ This matters because the dynamic program is indexed by position sets, not by numeric values alone....

Detailed mathematical approach

Problem Summary

Each challenge gives a target integer \(t\) and a short list \(a_1,\dots,a_n\). We may choose any nonempty subset of positions, use each chosen number exactly once, and combine them with binary operations. The implementations allow addition, multiplication, positive subtraction, and exact division, so every intermediate result remains a positive integer.

For one challenge, the score is the smallest possible sum of the chosen numbers that can produce \(t\). If no legal expression reaches the target, the score is \(0\). The final answer is the weighted sum of the 200 challenge scores, with weights \(3^r\), taken modulo \(1005075251\).

Mathematical Approach

Write \([n]=\{1,\dots,n\}\). For every nonempty subset \(A\subseteq [n]\), let

$\sigma(A)=\sum_{i\in A} a_i.$

The main task is to determine exactly which positive integers can be formed by expressions that use the positions in \(A\) and no others.

Step 1: Interpret legal formulas as binary expression trees

Any valid expression has a topmost operation whose left and right children are themselves valid expressions. Therefore the set of used positions splits into two disjoint nonempty parts \(B\) and \(C\) with

$A=B\cup C,\qquad B\cap C=\varnothing,\qquad B\ne\varnothing,\qquad C\ne\varnothing.$

This matters because the dynamic program is indexed by position sets, not by numeric values alone. If the same number appears twice in the input, those copies are still different leaves because they occupy different positions.

Step 2: Define the reachable-value set for each subset

Let \(V(A)\) be the set of all positive integers reachable from the positions in \(A\), using each chosen input exactly once. For a singleton subset we have

$V(\{i\})=\{a_i\}.$

For a larger subset \(A\), the reachable values come from combining two smaller disjoint subsets:

$V(A)=\bigcup_{\substack{B\cup C=A,\\B\cap C=\varnothing,\\B\ne\varnothing,\ C\ne\varnothing}} \operatorname{Combine}\bigl(V(B),V(C)\bigr).$

For each pair \(x\in V(B)\) and \(y\in V(C)\), the combination step inserts \(x+y\), \(xy\), \(x-y\) when \(x>y\), \(y-x\) when \(y>x\), \(x/y\) when \(y\mid x\), and \(y/x\) when \(x\mid y\).

Because subtraction is kept only when the result is positive and division is kept only when it is exact, all states contain positive integers only.

Step 3: Prove that the recurrence is complete

The recurrence captures every legal expression tree. The base case is immediate for a single leaf. For a larger expression, inspect the root: its two children use disjoint nonempty position sets \(B\) and \(C\). By induction, the child values lie in \(V(B)\) and \(V(C)\), so the root value is produced by the combination rule and lies in \(V(A)\).

The converse direction is equally important. Every value inserted by the recurrence is obtained by taking one valid expression over \(B\), one valid expression over \(C\), and joining them by an allowed operation. So each DP-generated value corresponds to a legal expression. This two-way induction shows that \(V(A)\) is exactly the reachable set.

Step 4: Extract the minimum score for one challenge

Once the reachable sets are known, the score of a single challenge is

$s=\min\left\{\sigma(A): \varnothing\ne A\subseteq [n],\ t\in V(A)\right\},$

with the convention \(s=0\) if the set is empty. The optimization target is the sum of the chosen input numbers, not the number of operations and not the size of the subset.

This is why the implementation precomputes \(\sigma(A)\) for every subset: the DP answers whether a subset can reach \(t\), and the subset sums turn that information into the required score.

Step 5: Combine the 200 independent challenge scores

If \(s_r\) denotes the score of challenge \(r\), then the global answer is

$\mathrm{Ans}=\sum_{r=1}^{200} 3^r s_r \pmod{1005075251}.$

The challenges do not interact mathematically, so the same subset DP is run for each one separately. Only the final weighted modular sum ties them together.

Worked Example

Take target \(t=2\) and numbers \((a_1,a_2,a_3)=(3,6,7)\). The singleton states are

$V(\{1\})=\{3\},\qquad V(\{2\})=\{6\},\qquad V(\{3\})=\{7\}.$

For the subset \(\{1,2\}\), combining \(3\) and \(6\) yields

$V(\{1,2\})\supseteq \{3+6,\ 3\cdot 6,\ 6-3,\ 6/3\}=\{9,18,3,2\}.$

So the target \(2\) is already reachable with subset sum \(\sigma(\{1,2\})=3+6=9\). The other two-element subsets give

$V(\{1,3\})\supseteq \{10,21,4\},\qquad V(\{2,3\})\supseteq \{13,42,1\}.$

No singleton reaches \(2\), and any three-element solution would use sum \(16\), which cannot beat \(9\). Therefore the challenge score is \(9\).

How the Code Works

The C++, Python, and Java implementations all represent subsets by bitmasks. They first precompute the sum of every mask by removing one set bit and reusing the previously computed sum. This makes the subset-score lookup constant time once the table has been built.

They then build the reachable sets in increasing mask order. A one-bit mask stores its lone input value. For a larger mask, the implementation enumerates nonempty proper submasks, pairs each submask with its complement, and evaluates all allowed operations on every pair of stored values. A hash-based set removes duplicates automatically, which is essential because many different expression trees can lead to the same integer.

Because addition and multiplication are symmetric and the implementation already checks both directions for subtraction and division, it only needs one representative of each unordered split. After all states have been built, the program scans every mask whose reachable set contains the target, keeps the minimum subset sum, and returns \(0\) if none work. The outer loop updates the current power of \(3\) modulo \(1005075251\) and accumulates the weighted total.

Complexity Analysis

Let \(n\) be the number of input values in one challenge. There are \(2^n-1\) nonempty masks. Precomputing all subset sums costs \(O(2^n)\) time and \(O(2^n)\) memory. Enumerating proper submasks across all masks gives the standard \(O(3^n)\) split count.

The dominant practical cost is the value pairing inside each split, so a precise bound is

$O\left(\sum_{A\subseteq [n]}\ \sum_{\substack{B\cup C=A,\\B\cap C=\varnothing}} |V(B)|\,|V(C)|\right).$

The memory usage is

$O\left(2^n+\sum_{\varnothing\ne A\subseteq [n]} |V(A)|\right).$

Since each challenge uses only a small input list, this exact set-based DP is feasible.

Footnotes and References

  1. Problem page: Project Euler 828
  2. Dynamic programming: Wikipedia - Dynamic programming
  3. Binary expression tree: Wikipedia - Binary expression tree
  4. Submask enumeration: cp-algorithms - Enumerating submasks of a bitmask
  5. Modular arithmetic: Wikipedia - Modular arithmetic

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

Previous: Problem 827 · All Project Euler solutions · Next: Problem 829

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