All Euler problems
Project Euler

Exploring the Number of Different Ways a Number Can Be Expressed as a Sum of Powers of 2

Define f(n) as the number of ways to express n as a sum of powers of 2, where each power of 2 is used at most twice. Find f(10^25).

Source sync May 21, 2026
Problem #0169
Level Level 06
Solved By 5,893
Languages C++, Python
Answer 178653872807
Length 385 words
dynamic_programmingrecursionsequence

Problem Statement

This archive keeps the full statement, math, and original media on the page.

Define \(f(0)=1\) and \(f(n)\) to be the number of different ways \(n\) can be expressed as a sum of integer powers of \(2\) using each power no more than twice.

For example, \(f(10)=5\) since there are five different ways to express \(10\): \begin {align*} & 1 + 1 + 8\\ & 1 + 1 + 4 + 4\\ & 1 + 1 + 2 + 2 + 4\\ & 2 + 4 + 4\\ & 2 + 8 \end {align*}

What is \(f(10^{25})\)?

Problem 169: Exploring the Number of Different Ways a Number Can Be Expressed as a Sum of Powers of 2

Mathematical Development

Definition. f(n)=∣{(c0,c1,c2,…):ci∈{0,1,2}, ∑i≥0ci⋅2i=n}∣f(n) = |\{(c_0, c_1, c_2, \ldots) : c_i \in \{0, 1, 2\}, \, \sum_{i \geq 0} c_i \cdot 2^i = n\}|.

Theorem 1 (Recurrence for ff). For all n≥0n \geq 0:

f(n)={1if n=0,f ⁣(⌊n/2⌋)if n is odd,f ⁣(n/2)+f ⁣(n/2−1)if n is even and n \geq2.f(n) = \begin{cases} 1 & \text{if } n = 0, \\ f\!\left(\lfloor n/2 \rfloor\right) & \text{if n is odd,} \\ f\!\left(n/2\right) + f\!\left(n/2 - 1\right) & \text{if n is even and n \geq 2.} \end{cases}

Proof. Consider the coefficient c0c_0 (the number of times 20=12^0 = 1 is used).

Case nn odd: We need c0c_0 odd, so c0=1c_0 = 1. Then ∑i≥1ci⋅2i=n−1\sum_{i \geq 1} c_i \cdot 2^i = n - 1. Dividing by 2: ∑i≥1ci⋅2i−1=(n−1)/2=⌊n/2⌋\sum_{i \geq 1} c_i \cdot 2^{i-1} = (n-1)/2 = \lfloor n/2 \rfloor. Relabeling ci′=ci+1c_i' = c_{i+1} gives a representation of ⌊n/2⌋\lfloor n/2 \rfloor with each ci′∈{0,1,2}c_i' \in \{0, 1, 2\}. This is a bijection, so f(n)=f(⌊n/2⌋)f(n) = f(\lfloor n/2 \rfloor).

Case nn even: We need c0c_0 even, so c0∈{0,2}c_0 \in \{0, 2\}.

  • If c0=0c_0 = 0: the remaining sum is nn, so ∑i≥1ci⋅2i=n\sum_{i \geq 1} c_i \cdot 2^i = n, giving ∑i≥0ci+1⋅2i=n/2\sum_{i \geq 0} c_{i+1} \cdot 2^i = n/2. This contributes f(n/2)f(n/2) representations.
  • If c0=2c_0 = 2: the remaining sum is n−2n - 2, so ∑i≥1ci⋅2i=n−2\sum_{i \geq 1} c_i \cdot 2^i = n - 2, giving ∑i≥0ci+1⋅2i=(n−2)/2=n/2−1\sum_{i \geq 0} c_{i+1} \cdot 2^i = (n-2)/2 = n/2 - 1. This contributes f(n/2−1)f(n/2 - 1) representations (valid since n≥2n \geq 2 ensures n/2−1≥0n/2 - 1 \geq 0).

Total: f(n)=f(n/2)+f(n/2−1)f(n) = f(n/2) + f(n/2 - 1). □\square

Theorem 2 (Subproblem count). The memoized computation of f(n)f(n) encounters at most O(log⁡2n)O(\log^2 n) distinct subproblems.

Proof. At recursion depth dd, the argument has the form ⌊n/2d⌋−j\lfloor n / 2^d \rfloor - j for some integer jj with 0≤j≤d0 \leq j \leq d. This is because each “even” branch produces two subproblems at argument ⌊n/2d+1⌋⋅(something)−j′\lfloor n/2^{d+1} \rfloor \cdot \text{(something)} - j', and the offset jj increases by at most 1 per even step. At depth dd, there are at most d+1d + 1 possible values of jj, giving at most ∑d=0⌊log⁡2n⌋(d+1)=O(log⁡2n)\sum_{d=0}^{\lfloor \log_2 n \rfloor} (d + 1) = O(\log^2 n) distinct subproblems. □\square

Lemma 1 (Base cases). f(0)=1f(0) = 1 (the empty sum) and f(1)=1f(1) = 1 (only c0=1c_0 = 1, all others 0).

Proof. f(0)f(0): the unique representation is ci=0c_i = 0 for all ii. f(1)f(1): c0=1c_0 = 1 is forced (only way to get an odd sum); then the remaining sum is 0, which has a unique representation. □\square

Lemma 2 (Correctness for n=1025n = 10^{25}). The recursion terminates since each step replaces nn by ⌊n/2⌋\lfloor n/2 \rfloor or ⌊n/2⌋−1\lfloor n/2 \rfloor - 1, strictly decreasing nn until reaching the base cases. The recursion depth is ⌈log⁡2(1025)⌉=84\lceil \log_2(10^{25}) \rceil = 84.

Proof. log⁡2(1025)=25log⁡210≈25×3.3219=83.05\log_2(10^{25}) = 25 \log_2 10 \approx 25 \times 3.3219 = 83.05, so the recursion depth is 84. □\square

Editorial

The recurrence already does all the heavy lifting. Looking at the coefficient of 202^0 splits the problem into one smaller subproblem when nn is odd and two smaller subproblems when nn is even. Because every recursive call roughly halves the argument, the state graph stays tiny even for 102510^{25}.

The implementation is therefore just memoized recursion. Each distinct value of nn is solved once, cached, and reused whenever it reappears from a different branch. That turns what looks like an exponential expansion into a small DAG of overlapping subproblems, making the exact count for 102510^{25} straightforward to obtain.

Pseudocode

Define a memoized function `f(n)`.

If `n` is zero, return 1.
If `n` is already cached, return the cached value.

If `n` is odd:
    the coefficient of 1 is forced to be 1,
    so return `f(n // 2)`.

If `n` is even:
    either use zero copies of 1 or two copies of 1,
    so return `f(n // 2) + f(n // 2 - 1)`.

Store the result in the cache and return it.
Evaluate the function at $10^{25}$.

Complexity Analysis

  • Time: O(log⁡2n)O(\log^2 n) subproblems, each requiring O(1)O(1) work (plus big-integer arithmetic for the values, which are O(log⁡n)O(\log n) bits). Total: O(log⁡2n⋅M(log⁡n))O(\log^2 n \cdot M(\log n)) where MM is multiplication cost, but since the values of ff are polynomially bounded in nn, O(log⁡3n)O(\log^3 n) suffices.
  • Space: O(log⁡2n)O(\log^2 n) for the memoization table.

For n=1025n = 10^{25}: depth ≈84\approx 84, subproblems ≤842/2≈3,528\leq 84^2 / 2 \approx 3{,}528.

Answer

178653872807\boxed{178653872807}

Code

Each problem page includes the exact C++ and Python source files from the local archive.

C++ project_euler/problem_169/solution.cpp
#include <bits/stdc++.h>
using namespace std;

/*
 * Problem 169: Number of ways to express n as sum of powers of 2,
 * each used at most twice. Find f(10^25).
 *
 * Recurrence:
 *   f(0) = 1
 *   f(n) = f(n/2)             if n is odd
 *   f(n) = f(n/2) + f(n/2-1)  if n is even
 *
 * We use Python-style big integers via strings or __int128.
 * Since 10^25 fits in unsigned 128-bit, we use __int128.
 */

typedef __int128 lll;

map<lll, long long> memo;

long long f(lll n) {
    if (n == 0) return 1;
    auto it = memo.find(n);
    if (it != memo.end()) return it->second;

    long long result;
    if (n % 2 == 1) {
        result = f(n / 2);
    } else {
        result = f(n / 2) + f(n / 2 - 1);
    }
    memo[n] = result;
    return result;
}

int main(){
    // 10^25
    lll n = 1;
    for (int i = 0; i < 25; i++) n *= 10;

    cout << (long long)f(n) << endl;
    return 0;
}