Project Euler Problem 310

Alice and Bob play the game Nim Square.

Project Euler Problem 310

Solution

Answer: 2586528661783

Let $G(n)$ be the Sprague–Grundy (nimber) value for a heap of size $n$ in Nim Square, where a move consists of removing a square number of stones.

A position $(a,b,c)$ is losing iff

$$G(a)\oplus G(b)\oplus G(c)=0,$$

where $\oplus$ denotes bitwise XOR.

1. Mathematical analysis

For a subtraction game (such as removing square numbers), the Grundy numbers satisfy:

$$G(0)=0,$$

and for $n\ge1$,

$$G(n)=\operatorname{mex} \left( {G(n-k^2)\mid k^2\le n} \right),$$

where mex means the smallest nonnegative integer not in the set.

So we compute $G(n)$ for all $0\le n\le100000$.

Key observation: count by nimber frequencies

Let

$$f(x)=#{n\in[0,N]\mid G(n)=x}.$$

Then the total number of ordered triples $(a,b,c)$ with XOR zero is

$$T = \sum_{x,y} f(x)f(y)f(x\oplus y),$$

because once $G(a)=x$ and $G(b)=y$, the third nimber must be

$$G(c)=x\oplus y.$$

But the problem wants only triples with

$$a\le b\le c.$$

We convert ordered triples into sorted triples.

Let:

  • $E$ = all equal triples $(x,x,x)$
  • $P$ = ordered triples with exactly two equal
  • $D$ = ordered triples with all distinct

Then

$$T=D+P+E.$$

A sorted triple contributes:

  • $6$ ordered permutations if all distinct,
  • $3$ if exactly two equal,
  • $1$ if all equal.

Hence the number of sorted losing positions is

$$L = \frac{D}{6} + \frac{P}{3} + E.$$

Rearranging:

$$L = \frac{T+P+5E}{6}.$$

Computing $P$ and $E$

For all equal:

$$x\oplus x\oplus x=x,$$

so the only losing all-equal triples are heaps with nimber $0$:

$$E=f(0).$$

For exactly two equal:

$$x\oplus x\oplus y=y,$$

so the singleton heap must have nimber $0$.

If $M=N+1$ is the number of heap sizes, then:

$$P = 3,f(0)(M-1),$$

(the factor 3 accounts for which position is the singleton).

We validate the method on the example $N=29$, obtaining:

$$1160,$$

matching the problem statement.

2. Python implementation

import math

def nim_square_losing_positions(N):
    # All square moves
    squares = [i * i for i in range(1, int(math.isqrt(N)) + 1)]

    # Compute Grundy values
    grundy = [0] * (N + 1)
    max_g = 0

    for n in range(1, N + 1):
        seen = 0

        # Collect reachable Grundy values
        for s in squares:
            if s > n:
                break
            seen |= 1 << grundy[n - s]

        # mex(seen)
        mex = 0
        while (seen >> mex) & 1:
            mex += 1

        grundy[n] = mex
        max_g = max(max_g, mex)

    # Frequency of each Grundy value
    freq = [0] * (max_g + 1)
    for g in grundy:
        freq[g] += 1

    # Count ordered losing triples
    ordered_total = 0
    for x, fx in enumerate(freq):
        for y, fy in enumerate(freq):
            z = x ^ y
            if z <= max_g:
                ordered_total += fx * fy * freq[z]

    f0 = freq[0]
    M = N + 1

    # Exactly two equal
    P = 3 * f0 * (M - 1)

    # All equal
    E = f0

    # Convert ordered -> sorted
    losing_positions = (ordered_total + P + 5 * E) // 6

    return losing_positions

# Check the example
print(nim_square_losing_positions(29))      # 1160

# Solve the problem
print(nim_square_losing_positions(100000))

3. Code walkthrough

  1. Generate square moves
squares = [i*i for i in range(...)]

Precomputes all legal removals. 2. Compute Grundy values

seen |= 1 << grundy[n - s]

Uses a bitmask to store reachable nimbers efficiently. 3. mex calculation

while (seen >> mex) & 1:
    mex += 1

Finds the smallest missing nimber. 4. Frequency table

freq[g] += 1

Counts how many heap sizes have each nimber. 5. Count ordered losing triples

z = x ^ y
ordered_total += fx * fy * freq[z]

Since XOR must be zero. 6. Correct for ordering

Apply:

$$L=\frac{T+P+5E}{6}.$$

Example verification

For $N=29$, the program returns:

$$1160$$

which exactly matches the problem statement.

4. Final verification

  • Grundy values up to $100000$ remain small (maximum nimber found: $74$), making the frequency method efficient.
  • The sample case matches perfectly.
  • The resulting magnitude ($\sim 2.6\times10^{12}$) is reasonable given there are about

$$\binom{100003}{3}\approx 1.67\times10^{14}$$

sorted triples total.

Answer: 2586528661783