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).
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. .
Theorem 1 (Recurrence for ). For all :
Proof. Consider the coefficient (the number of times is used).
Case odd: We need odd, so . Then . Dividing by 2: . Relabeling gives a representation of with each . This is a bijection, so .
Case even: We need even, so .
- If : the remaining sum is , so , giving . This contributes representations.
- If : the remaining sum is , so , giving . This contributes representations (valid since ensures ).
Total: .
Theorem 2 (Subproblem count). The memoized computation of encounters at most distinct subproblems.
Proof. At recursion depth , the argument has the form for some integer with . This is because each “even” branch produces two subproblems at argument , and the offset increases by at most 1 per even step. At depth , there are at most possible values of , giving at most distinct subproblems.
Lemma 1 (Base cases). (the empty sum) and (only , all others 0).
Proof. : the unique representation is for all . : is forced (only way to get an odd sum); then the remaining sum is 0, which has a unique representation.
Lemma 2 (Correctness for ). The recursion terminates since each step replaces by or , strictly decreasing until reaching the base cases. The recursion depth is .
Proof. , so the recursion depth is 84.
Editorial
The recurrence already does all the heavy lifting. Looking at the coefficient of splits the problem into one smaller subproblem when is odd and two smaller subproblems when is even. Because every recursive call roughly halves the argument, the state graph stays tiny even for .
The implementation is therefore just memoized recursion. Each distinct value of 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 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: subproblems, each requiring work (plus big-integer arithmetic for the values, which are bits). Total: where is multiplication cost, but since the values of are polynomially bounded in , suffices.
- Space: for the memoization table.
For : depth , subproblems .
Answer
Code
Each problem page includes the exact C++ and Python source files from the local archive.
#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;
}
"""
Problem 169: Number of ways to express n as sum of powers of 2,
each power 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
"""
import sys
sys.setrecursionlimit(10000)
memo = {}
def f(n):
if n == 0:
return 1
if n in memo:
return memo[n]
if n % 2 == 1:
result = f(n // 2)
else:
result = f(n // 2) + f(n // 2 - 1)
memo[n] = result
return result
print(f(10**25))