All Euler problems
Project Euler

Bitwise Recursion

Define the function f:N_0 x N_0 -> N_0 by: f(n, k) = n & if k = 0, f(n + k, floor(k/2)) & if k > 0, where + denotes bitwise XOR. Let S(N) = sum_(k=0)^N sum_(n=0)^N f(n, k). Find S(10^18) mod (10^9...

Source sync Apr 19, 2026
Problem #0811
Level Level 32
Solved By 264
Languages C++, Python
Answer 327287526
Length 467 words
modular_arithmeticdynamic_programmingdigit_dp

Problem Statement

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

Let \(b(n)\) be the largest power of \(2\) that divides \(n\). For example \(b(24) = 8\).

Define the recursive function: \begin {align*} A(0) &= 1 \\ A(2n) &= 3A(n) + 5A(2n - b(n)) \qquad \text {for } n > 0 \\ A(2n + 1) &= A(n) \end {align*}

and let \(H(t, r) = A\left ((2^t + 1)^r\right )\).

You are given \(H(3, 2) = A(81) = 636056\).

Find \(H(10^{14} + 31, 62)\). Give your answer modulo \(\num {1000062031}\).

Problem 811: Bitwise Recursion

Mathematical Foundation

Let B=log2(N+1)B = \lceil \log_2(N+1) \rceil and write any non-negative integer kk in binary as k=i=0Lbi2ik = \sum_{i=0}^{L} b_i 2^i with bi{0,1}b_i \in \{0,1\}.

Lemma 1 (Closed form for ff). For all n,kN0n, k \in \mathbb{N}_0,

f(n,k)=ng(k),g(k):=t=0k/2t.f(n, k) = n \oplus g(k), \qquad g(k) := \bigoplus_{t=0}^{\infty} \lfloor k / 2^t \rfloor.

Proof. Define kt=k/2tk_t = \lfloor k / 2^t \rfloor. The recursion unfolds as:

  • Step 0: accumulator =n= n, remaining key =k0=k= k_0 = k.
  • Step 1: accumulator =nk0= n \oplus k_0, remaining key =k1= k_1.
  • Step tt: accumulator =nk0k1kt1= n \oplus k_0 \oplus k_1 \oplus \cdots \oplus k_{t-1}, remaining key =kt= k_t.

The recursion terminates when kt=0k_t = 0, i.e., when t>log2kt > \lfloor \log_2 k \rfloor. The final accumulator is nt0kt=ng(k)n \oplus \bigoplus_{t \ge 0} k_t = n \oplus g(k). \square

Lemma 2 (Suffix XOR characterisation of gg). Bit jj of g(k)g(k) equals the suffix XOR parity of the binary representation of kk starting at position jj:

g(k)j=ijbi.g(k)_j = \bigoplus_{i \ge j} b_i.

Proof. Bit jj of k/2t\lfloor k/2^t \rfloor is bj+tb_{j+t}. Therefore

g(k)j=t=0Lbj+t=ijbi.g(k)_j = \bigoplus_{t=0}^{L} b_{j+t} = \bigoplus_{i \ge j} b_i.

This is a finite sum since bi=0b_i = 0 for i>Li > L. \square

Theorem 1 (Involution). The function gg is an involution on N0\mathbb{N}_0, i.e., g(g(k))=kg(g(k)) = k for all kk.

Proof. Over GF(2)\mathrm{GF}(2), represent the binary digits of kk as a column vector b=(b0,b1,,bL)\mathbf{b} = (b_0, b_1, \ldots, b_L)^\top. The map gg acts as bMb\mathbf{b} \mapsto M\mathbf{b}, where MM is the lower-triangular matrix with Mij=1M_{ij} = 1 for iji \le j (i.e., all entries on and above the diagonal are 1). Explicitly, the (i,j)(i,j)-entry of M2M^2 over GF(2)\mathrm{GF}(2) is

(M2)ij=MiMj==ij1=(ji+1)mod2.(M^2)_{ij} = \bigoplus_{\ell} M_{i\ell} \cdot M_{\ell j} = \bigoplus_{\ell = i}^{j} 1 = (j - i + 1) \bmod 2.

Wait — let us index correctly. We have Mij=1M_{ij} = 1 if jij \ge i (upper-triangular all-ones). Then (M2)ij==ij1(M^2)_{ij} = \bigoplus_{\ell = i}^{j} 1 when jij \ge i, which equals (ji+1)mod2(j - i + 1) \bmod 2. This is 1 iff j=ij = i, so M2=IM^2 = I over GF(2)\mathrm{GF}(2). Therefore g(g(k))=kg(g(k)) = k. \square

Theorem 2 (Decomposition of S(N)S(N)). Write f(n,k)=ng(k)f(n,k) = n \oplus g(k). Then

S(N)=j=0B12jCj,S(N) = \sum_{j=0}^{B-1} 2^j \cdot C_j,

where Cj=Aj(N+1Bj)+(N+1Aj)BjC_j = A_j(N+1 - B_j) + (N+1 - A_j) B_j, with Aj={n[0,N]:nj=1}A_j = |\{n \in [0,N] : n_j = 1\}| and Bj={k[0,N]:g(k)j=1}B_j = |\{k \in [0,N] : g(k)_j = 1\}|.

Proof. We have

S(N)=k=0Nn=0N(ng(k))=j=0B12j{(n,k)[0,N]2:(ng(k))j=1}.S(N) = \sum_{k=0}^{N} \sum_{n=0}^{N} (n \oplus g(k)) = \sum_{j=0}^{B-1} 2^j \cdot |\{(n,k) \in [0,N]^2 : (n \oplus g(k))_j = 1\}|.

Bit jj of ng(k)n \oplus g(k) is 1 iff njg(k)jn_j \ne g(k)_j. Counting over independent choices of nn and kk:

Cj={n:nj=1}{k:g(k)j=0}+{n:nj=0}{k:g(k)j=1}C_j = |\{n : n_j = 1\}| \cdot |\{k : g(k)_j = 0\}| + |\{n : n_j = 0\}| \cdot |\{k : g(k)_j = 1\}| =Aj(N+1Bj)+(N+1Aj)Bj.= A_j(N+1 - B_j) + (N+1 - A_j)B_j.

\square

Lemma 3 (Computing AjA_j). The count Aj={n[0,N]:bit j of n is 1}A_j = |\{n \in [0,N] : \text{bit } j \text{ of } n \text{ is } 1\}| is given by standard bit-counting:

Aj=N+12j+12j+max ⁣(0,  (N+1)mod2j+12j).A_j = \left\lfloor \frac{N+1}{2^{j+1}} \right\rfloor \cdot 2^j + \max\!\Big(0,\; (N+1) \bmod 2^{j+1} - 2^j\Big).

Proof. Among {0,1,,N}\{0, 1, \ldots, N\}, bit jj cycles with period 2j+12^{j+1}: it is 0 for 2j2^j values then 1 for 2j2^j values. Counting complete cycles plus the partial remainder yields the formula. \square

Lemma 4 (Computing BjB_j via digit DP). The count Bj={k[0,N]:g(k)j=1}B_j = |\{k \in [0,N] : g(k)_j = 1\}| can be computed using a digit dynamic programming approach that processes the bits of NN from MSB to LSB, tracking: (i) whether the prefix of kk is still tight to NN, and (ii) the running suffix XOR parity from bit jj onward. This requires O(B)O(B) states per bit position jj.

Proof. The digit DP is a standard technique for counting integers in [0,N][0,N] satisfying a bitwise predicate. For each bit jj, the suffix XOR parity involves bits at positions j\ge j, which are determined as we process from MSB down. The tight/free flag doubles the state count, giving O(B)O(B) states per bit and O(B2)O(B^2) total across all jj. \square

Editorial

f(n, k) = n if k = 0 = f(n XOR k, k >> 1) if k > 0 Key insight: f(n, k) = n XOR g(k) where g(k) = XOR of all right-shifts of k. Bit j of g(k) = XOR of bits j, j+1, j+2, … of k (suffix XOR parity). We compute S(N) = sum_{k=0}^{N} sum_{n=0}^{N} f(n, k) mod (10^9 + 7) = sum_{k=0}^{N} sum_{n=0}^{N} (n XOR g(k)). We compute A_j: count of n in [0,N] with bit j set. We then compute B_j via digit DP on k in [0,N]. Finally, tracking suffix XOR parity from bit j onward.

Pseudocode

Compute A_j: count of n in [0,N] with bit j set
Compute B_j via digit DP on k in [0,N]
tracking suffix XOR parity from bit j onward
DP over bits B-1 down to 0
State: (tight, suffix_xor_parity)
tight: whether k's prefix matches N's prefix exactly
suffix_xor_parity: running XOR of bits at positions >= target_bit
Returns count of k in [0,N] with suffix_xor_parity = 1 at end

Complexity Analysis

  • Time: O(B2)O(B^2) where B=log2(N+1)60B = \lceil \log_2(N+1) \rceil \approx 60 for N=1018N = 10^{18}. The digit DP for each of BB bit positions jj runs in O(B)O(B) time, giving O(B2)=O(3600)O(B^2) = O(3600) total operations.
  • Space: O(B)O(B) for the DP states (constant number of states per bit level).

Answer

327287526\boxed{327287526}

Code

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

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

/*
 * Problem 811: Bitwise Recursion
 *
 * f(n, k) = n                    if k = 0
 *         = f(n XOR k, k >> 1)   if k > 0
 *
 * Key insight: f(n, k) = n XOR g(k), where g(k) = k XOR (k>>1) XOR (k>>2) XOR ...
 * Bit j of g(k) = XOR of bits j, j+1, j+2, ... of k (suffix XOR parity).
 *
 * S(N) = sum_{k=0}^{N} sum_{n=0}^{N} (n XOR g(k))
 *
 * For each bit position j, count pairs (n,k) in [0,N]^2 where
 * bit j of (n XOR g(k)) is 1, then S(N) = sum_j 2^j * count_j.
 */

const long long MOD = 1e9 + 7;

long long power(long long base, long long exp, long long mod) {
    long long result = 1;
    base %= mod;
    while (exp > 0) {
        if (exp & 1) result = result * base % mod;
        base = base * base % mod;
        exp >>= 1;
    }
    return result;
}

// Count k in [0..N] where suffix XOR parity from bit j onward is 1
// Uses digit DP on binary representation of N
long long count_suffix_xor_odd(long long N, int j) {
    if (N < 0) return 0;
    int B = 63 - __builtin_clzll(N + 1);  // number of bits needed
    if (j > B) return 0;

    // Extract bits of N from MSB to LSB
    vector<int> bits(B + 1);
    for (int i = B; i >= 0; i--) {
        bits[B - i] = (N >> i) & 1;
    }

    // dp[tight][parity] = count
    // tight: are we still bounded by N?
    // parity: XOR of bits at positions >= j seen so far
    map<pair<bool,int>, long long> dp;
    dp[{true, 0}] = 1;

    for (int i = 0; i <= B; i++) {
        int actual_bit_pos = B - i;
        map<pair<bool,int>, long long> new_dp;
        for (auto& [state, cnt] : dp) {
            auto [tight, par] = state;
            int max_d = tight ? bits[i] : 1;
            for (int d = 0; d <= max_d; d++) {
                bool new_tight = tight && (d == bits[i]);
                int new_par = par;
                if (actual_bit_pos >= j) {
                    new_par = par ^ d;
                }
                new_dp[{new_tight, new_par}] += cnt;
            }
        }
        dp = new_dp;
    }

    long long result = 0;
    for (auto& [state, cnt] : dp) {
        if (state.second == 1) result += cnt;
    }
    return result;
}

// Count n in [0..N] with bit j set
long long count_bit_set(long long N, int j) {
    if (N < 0) return 0;
    long long full = (N + 1) >> (j + 1);
    long long rem = (N + 1) & ((1LL << (j + 1)) - 1);
    return full * (1LL << j) + max(0LL, rem - (1LL << j));
}

long long solve(long long N) {
    int B = 63;
    if (N > 0) B = 63 - __builtin_clzll(N);

    long long total = 0;
    for (int j = 0; j <= B; j++) {
        long long ones_n = count_bit_set(N, j) % MOD;
        long long zeros_n = ((N + 1) % MOD - ones_n % MOD + MOD) % MOD;

        long long ones_k = count_suffix_xor_odd(N, j) % MOD;
        long long zeros_k = ((N + 1) % MOD - ones_k % MOD + MOD) % MOD;

        // Pairs where n_j XOR g(k)_j = 1
        long long count_j = (ones_n * zeros_k % MOD + zeros_n * ones_k % MOD) % MOD;
        total = (total + count_j % MOD * power(2, j, MOD) % MOD) % MOD;
    }
    return total;
}

// Brute force for verification
long long g_func(long long k) {
    long long result = 0;
    while (k) {
        result ^= k;
        k >>= 1;
    }
    return result;
}

long long solve_brute(int N) {
    long long total = 0;
    for (int k = 0; k <= N; k++) {
        long long gk = g_func(k);
        for (int n = 0; n <= N; n++) {
            total += (n ^ gk);
        }
    }
    return total;
}

int main() {
    // Cross-verify on small cases
    for (int N = 1; N <= 20; N++) {
        long long brute = solve_brute(N);
        long long dp = solve(N);
        assert(brute % MOD == dp);
    }

    // Compute answer for N = 10^18
    long long N = 1000000000000000000LL;
    cout << solve(N) << endl;

    return 0;
}