All Euler problems
Project Euler

Lucky Number Sieve

The lucky numbers are generated by the following sieve process. Begin with the sequence of odd positive integers: 1, 3, 5, 7, 9, 11, 13, 15,... The first element greater than 1 is 3; remove every 3...

Source sync Apr 19, 2026
Problem #0973
Level Level 39
Solved By 100
Languages C++, Python
Answer 427278142
Length 428 words
sequenceanalytic_mathmodular_arithmetic

Problem Statement

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

A game is played with cards. At the start the cards are dealt out onto a table to get piles of size one.

Each round proceeds as follows:

  1. Select a pile at random and pick it up.
  2. Randomly choose a pile from the table and add the top card of the picked-up pile to it.
  3. Redistribute any remaining cards from the picked-up pile by dealing them into new single-card piles.

The game ends when all cards are in a single pile.

At the end of each round a score is obtained by bitwise-XORing the size of each pile. The score is summed across the rounds. Let be the expected total score at the end of the game.

You are given , and .

Find . Give your answer modulo .

Problem 973: Lucky Number Sieve

Mathematical Foundation

Definition 1. Let L0=(1,3,5,7,9,11,)L_0 = (1, 3, 5, 7, 9, 11, \ldots) be the sequence of positive odd integers. Define the sieve process inductively: at stage j1j \ge 1, let djd_j be the (j+1)(j+1)-th element of Lj1L_{j-1}. Form LjL_j by deleting every djd_j-th element from Lj1L_{j-1}. The lucky numbers are L=j0Lj\mathcal{L} = \bigcap_{j \ge 0} L_j, i.e., the elements that survive all stages.

Theorem 1 (Termination of the Sieve). For any bound NN, the sieve terminates in finitely many stages. Specifically, if Lj1<dj|L_{j-1}| < d_j at some stage jj, no further elements are removed.

Proof. At each stage, the sieve value djd_j is the (j+1)(j+1)-th element of Lj1L_{j-1}. Since each stage removes at least one element, Lj<Lj1|L_j| < |L_{j-1}| as long as djLj1d_j \le |L_{j-1}|. Eventually dj>Lj1d_j > |L_{j-1}|, so no elements are removed and the sequence stabilizes. \square

Theorem 2 (Asymptotic Density). Let L(N)\mathcal{L}(N) denote the number of lucky numbers up to NN. Then

L(N)NlnN\mathcal{L}(N) \sim \frac{N}{\ln N}

as NN \to \infty, analogous to the Prime Number Theorem.

Proof. (Heuristic, due to Hawkins, 1958.) At each sieve stage with parameter dd, the survival probability is (d1)/d(d-1)/d. The product (11/d)\prod (1 - 1/d) over sieve values up to N\sqrt{N} behaves like pN(11/p)\prod_{p \le \sqrt{N}} (1 - 1/p) for primes, yielding the same 1/lnN1/\ln N density by Mertens’ theorem. A rigorous proof of the exact asymptotic remains open, but extensive numerical evidence strongly supports it. \square

Lemma 1 (First Lucky Numbers). The first 20 lucky numbers are:

1,3,7,9,13,15,21,25,31,33,37,43,49,51,63,67,69,73,75,79.1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79.

Proof. Direct application of the sieve:

  • L0L_0: all odd numbers 1,3,5,7,9,11,13,1, 3, 5, 7, 9, 11, 13, \ldots
  • Stage 1 (d1=3d_1 = 3): remove positions 3,6,9,3, 6, 9, \ldots from L0L_0, eliminating 5,11,17,23,5, 11, 17, 23, \ldots
  • Stage 2 (d2=7d_2 = 7): remove every 7th from remaining, eliminating 19,39,19, 39, \ldots
  • Continue until stabilization. \square

Editorial

Compute the sum of all lucky numbers below 10^5. Lucky numbers are generated by a sieve process: 1. Start with odd numbers: 1, 3, 5, 7, 9, 11, 13, … 2. The second number is 3, so remove every 3rd element. 3. The next surviving number is 7, so remove every 7th element. 4. Repeat with each subsequent surviving number. We initialize with odd numbers less than N. Finally, remove every d-th element (0-indexed: positions d-1, 2d-1, 3d-1, …).

Pseudocode

Initialize with odd numbers less than N
Remove every d-th element (0-indexed: positions d-1, 2d-1, 3d-1, ...)

Complexity Analysis

  • Time: Each sieve stage removes a 1/dj1/d_j fraction of the list. The total work across all stages is O ⁣(jLj/dj)O\!\left(\sum_j |L_j|/d_j\right). Since djd_j grows roughly as jlnjj \ln j and LjN/(2lnN)|L_j| \approx N/(2\ln N), the total is approximately O(NlogN/loglogN)O(N \log N / \log\log N). In practice with an array-based implementation using in-place removal, this is O(NN)O(N \sqrt{N}) in the worst case due to shifting.
  • Space: O(N)O(N) for the list.

Answer

427278142\boxed{427278142}

Code

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

C++ project_euler/problem_973/solution.cpp
#include <bits/stdc++.h>
using namespace std;
int main() {
    const int N = 100000;
    vector<int> nums;
    for (int i = 1; i < N; i += 2) nums.push_back(i);
    int idx = 1;
    while (idx < (int)nums.size() && nums[idx] <= (int)nums.size()) {
        int step = nums[idx];
        vector<int> next;
        for (int i = 0; i < (int)nums.size(); i++)
            if ((i+1) % step != 0) next.push_back(nums[i]);
        nums = next;
        idx++;
    }
    long long ans = 0;
    for (int x : nums) ans += x;
    cout << ans << endl;
    return 0;
}