All Euler problems
Project Euler

Combinatorial Game Values

In the game of Nim with heaps of sizes 1, 2,..., n, the Sprague--Grundy value is G(n) = 1 + 2 +... + n (XOR sum). Find the number of n <= 10^6 for which G(n) = 0 (i.e., the second player wins).

Source sync Apr 19, 2026
Problem #0923
Level Level 38
Solved By 119
Languages C++, Python
Answer 740759929
Length 279 words
modular_arithmeticgame_theorycombinatorics

Problem Statement

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

A Young diagram is a finite collection of (equally-sized) squares in a grid-like arrangement of rows and columns, such that

  • the left-most squares of all rows are aligned vertically;
  • the top squares of all columns are aligned horizontally;
  • the rows are non-increasing in size as we move top to bottom;
  • the columns are non-increasing in size as we move left to right.

Two examples of Young diagrams are shown below.

0922_youngs_game_diagrams.png

Two players Right and Down play a game on several Young diagrams, all disconnected from each other. Initially, a token is placed in the top-left square of each diagram. Then they take alternating turns, starting with Right. On Right's turn, Right selects a token on one diagram and moves it one square to the right. On Down's turn, Down selects a token on one diagram and moves it one square downwards. A player unable to make a legal move on their turn loses the game.

For we define an -staircase to be the Young diagram where the bottom-right frontier consists of steps of vertical height and horizontal length . Shown below are four examples of staircases with respectively .

0922_youngs_game_staircases.png

Additionally, define the weight of an -staircase to be .

Let be the number ways of choosing staircases, each having weight not exceeding , upon which Right (moving first in the game) will win the game assuming optimal play. Different orderings of the same set of staircases are to be counted separately.

For example, is illustrated below, with tokens as grey circles drawn in their initial positions.

0922_youngs_game_example.png

You are also given .

Find giving your answer modulo .

Problem 923: Combinatorial Game Values

Mathematical Foundation

Theorem 1 (Sprague—Grundy). In any impartial combinatorial game, every position has a non-negative integer Grundy value. A position is a loss for the player to move if and only if its Grundy value is 00. For a disjunctive sum of games, the Grundy value is the XOR of the individual Grundy values.

Proof. (Sketch.) Define G(P)=mex{G(Q):Q reachable from P}\mathcal{G}(P) = \mathrm{mex}\{\mathcal{G}(Q) : Q \text{ reachable from } P\}. One verifies by strong induction that G(P)=0\mathcal{G}(P) = 0 iff every move leads to a position with G>0\mathcal{G} > 0 (losing), and G(P)>0\mathcal{G}(P) > 0 iff some move leads to G=0\mathcal{G} = 0 (winning). The XOR property for disjunctive sums follows from the Nim-value characterization: G(G1+G2)=G(G1)G(G2)\mathcal{G}(G_1 + G_2) = \mathcal{G}(G_1) \oplus \mathcal{G}(G_2), proved by verifying the mex condition using the binary representation. \square

Theorem 2 (XOR Prefix Sum). For all n0n \geq 0:

k=1nk={nif n0(mod4),1if n1(mod4),n+1if n2(mod4),0if n3(mod4).\bigoplus_{k=1}^{n} k = \begin{cases} n & \text{if } n \equiv 0 \pmod{4}, \\ 1 & \text{if } n \equiv 1 \pmod{4}, \\ n+1 & \text{if } n \equiv 2 \pmod{4}, \\ 0 & \text{if } n \equiv 3 \pmod{4}. \end{cases}

Proof. We first establish the key identity: for every m0m \geq 0,

4m(4m+1)(4m+2)(4m+3)=0.(*)4m \oplus (4m+1) \oplus (4m+2) \oplus (4m+3) = 0. \tag{*}

To see this, note that 4m4m and 4m+14m+1 agree on all bits except bit 0, so 4m(4m+1)=14m \oplus (4m+1) = 1. Similarly 4m+24m+2 and 4m+34m+3 agree except on bit 0, giving (4m+2)(4m+3)=1(4m+2) \oplus (4m+3) = 1. Hence the XOR of all four is 11=01 \oplus 1 = 0.

Now write n=4q+rn = 4q + r with r{0,1,2,3}r \in \{0,1,2,3\}. By ()(*), k=14q1k=k=04q1k=0\bigoplus_{k=1}^{4q-1} k = \bigoplus_{k=0}^{4q-1} k = 0 (the blocks {0,1,2,3},{4,5,6,7},\{0,1,2,3\}, \{4,5,6,7\}, \ldots each XOR to 0). Then:

  • r=0r = 0: k=04qk=04q=4q=n\bigoplus_{k=0}^{4q} k = 0 \oplus 4q = 4q = n.
  • r=1r = 1: k=04q+1k=n(4q+1)=4q(4q+1)=1\bigoplus_{k=0}^{4q+1} k = n \oplus (4q+1) = 4q \oplus (4q+1) = 1.
  • r=2r = 2: k=04q+2k=1(4q+2)=4q+3=n+1\bigoplus_{k=0}^{4q+2} k = 1 \oplus (4q+2) = 4q + 3 = n + 1.
  • r=3r = 3: k=04q+3k=(n+1)n=(4q+3)(4q+3)=0\bigoplus_{k=0}^{4q+3} k = (n+1) \oplus n = (4q+3) \oplus (4q+3) = 0. \square

Theorem 3 (Counting Second-Player Wins). The number of nNn \leq N with G(n)=0G(n) = 0 is (N3)/4+1\lfloor (N-3)/4 \rfloor + 1 for N3N \geq 3, and 00 for N<3N < 3.

Proof. By Theorem 2, G(n)=0G(n) = 0 if and only if n3(mod4)n \equiv 3 \pmod{4}. The integers in {1,2,,N}\{1, 2, \ldots, N\} satisfying n3(mod4)n \equiv 3 \pmod{4} form the arithmetic progression 3,7,11,3, 7, 11, \ldots. The largest such nNn \leq N is 4(N3)/4+34\lfloor(N-3)/4\rfloor + 3, so the count is (N3)/4+1\lfloor(N-3)/4\rfloor + 1. \square

For N=106N = 10^6: (1063)/4+1=999997/4+1=249999+1=250000\lfloor(10^6 - 3)/4\rfloor + 1 = \lfloor 999997/4 \rfloor + 1 = 249999 + 1 = 250000.

Editorial

Nim heaps 1..n, G(n) = XOR(1..n). Count n <= 10^6 with G(n) = 0. Key ideas:. We use dynamic programming over the state space implied by the derivation, apply each admissible transition, and read the answer from the final table entry.

Pseudocode

    If N < 3 then
        Return 0
    Return floor((N - 3) / 4) + 1

Complexity Analysis

  • Time: O(1)O(1) — a single arithmetic computation.
  • Space: O(1)O(1).

Answer

740759929\boxed{740759929}

Code

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

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

/*
 * Problem 923: Combinatorial Game Values
 *
 * Nim heaps 1..n. G(n) = XOR(1..n).
 * Count n <= 10^6 with G(n) = 0.
 *
 * XOR prefix period-4 pattern:
 *   n%4=0: n,  n%4=1: 1,  n%4=2: n+1,  n%4=3: 0
 *
 * Proof: 4k XOR (4k+1) XOR (4k+2) XOR (4k+3) = 0.
 * G(n) = 0 iff n = 3 mod 4.
 * Count = (N-3)/4 + 1 = 250000.
 */

int xor_prefix(int n) {
    switch (n % 4) {
        case 0: return n;
        case 1: return 1;
        case 2: return n + 1;
        case 3: return 0;
    }
    return -1;
}

int main() {
    int N = 1000000;
    int answer = (N - 3) / 4 + 1;
    cout << answer << endl;

    // Verify
    int brute = 0, xv = 0;
    for (int n = 1; n <= 10000; n++) {
        xv ^= n;
        if (xv == 0) brute++;
        assert(xv == xor_prefix(n));
    }
    assert(brute == (10000 - 3) / 4 + 1);

    return 0;
}