All Euler problems
Project Euler

Project Euler Problem 409: Nim Extreme

Consider nim positions where: 1. There are n non-empty piles. 2. Each pile has size less than 2^n. 3. No two piles share the same size. Define W(n) as the number of winning positions (the first pla...

Source sync Apr 19, 2026
Problem #0409
Level Level 22
Solved By 535
Languages C++, Python
Answer 253223948
Length 477 words
modular_arithmeticgame_theorybrute_force

Problem Statement

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

Let \(n\) be a positive integer. Consider nim positions where:

  • There are \(n\) non-empty piles.

  • Each pile has size less than \(2^n\).

  • No two piles have the same size.

Let \(W(n)\) be the number of winning nim positions satisfying the above conditions (a position is winning if the first player has a winning strategy). For example, \(W(1) = 1\), \(W(2) = 6\), \(W(3) = 168\) and \(W(5) = 19764360\) and \(W(100) \mod \num {1000000007} = 384777056\).

Find \(W(\num {10000000} \mod \num {1000000007})\).

Project Euler Problem 409: Nim Extreme

Solution

Answer

W(10,000,000) mod 10^9 + 7 = 253223948

Mathematical Derivation

Setting up the counting. The heap sizes are distinct values from {1, 2, …, 2^n - 1}, and the piles are distinguishable (ordered). A position is losing if and only if the XOR (nim-sum) of all heap sizes is zero.

Let L(n) be the number of unordered n-element subsets of {1, …, 2^n - 1} with XOR equal to 0. Then:

W(n) = n! * (C(2^n - 1, n) - L(n))

Computing L(n) via Fourier analysis on GF(2)^n. The set {1, …, 2^n - 1} is exactly the set of nonzero elements of the vector space GF(2)^n.

Using the orthogonality of characters on GF(2)^n:

L(n) = (1 / 2^n) * [ C(2^n - 1, n) + (2^n - 1) * E_n ]

where

E_n = sum_{j=0}^{n} C(p, j) * C(q, n-j) * (-1)^{n-j}

with p = 2^{n-1} - 1 and q = 2^{n-1}. This comes from the fact that for every nonzero character a in GF(2)^n, exactly p = 2^{n-1} - 1 nonzero elements v satisfy a . v = 0 and q = 2^{n-1} satisfy a . v = 1.

Simplifying E_n via generating functions. The key insight is that E_n is the coefficient [x^n] of the product:

(1+x)^p * (1-x)^q = (1+x)^{2^{n-1}-1} * (1-x)^{2^{n-1}}
                   = (1-x) * (1-x^2)^{2^{n-1}-1}

Setting m = 2^{n-1} - 1 and h = floor(n/2):

  • n even: E_n = (-1)^h * C(m, h)
  • n odd: E_n = (-1)^{(n+1)/2} * C(m, (n-1)/2)

Final formula for W(n). Substituting and simplifying:

W(n) = n! * (2^n - 1) / 2^n * (C(2^n - 1, n) - E_n)   (mod 10^9 + 7)

where division by 2^n is performed via modular inverse.

Complexity

  • Time: O(n) — one loop for factorial and falling factorial, plus O(log M) for modular exponentiations.
  • Space: O(1) — only a constant number of accumulators.

Verification

nW(n)Matches Expected
11Yes
26Yes
3168Yes
519,764,360Yes
100 mod 10^9+7384,777,056Yes

Correctness

Theorem. The method described above computes exactly the quantity requested in the problem statement.

Proof. The preceding analysis identifies the admissible objects and derives the formula, recurrence, or exhaustive search carried out by the algorithm. The computation evaluates exactly that specification, so every valid contribution is included once and no invalid contribution is counted. Therefore the returned value is the required answer. \square

Answer

253223948\boxed{253223948}

Code

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

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

/*
 * Project Euler Problem 409: Nim Extreme
 *
 * W(n) = n! * (2^n - 1) / 2^n * (C(2^n-1, n) - E_n)  mod M
 *
 * where E_n = (-1)^h * C(2^{n-1}-1, h),  h = n/2      (n even)
 *       E_n = (-1)^{(n+1)/2} * C(2^{n-1}-1, (n-1)/2)  (n odd)
 *
 * All modular arithmetic with M = 10^9 + 7.
 */

static const long long M = 1000000007LL;

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

long long modinv(long long a, long long mod) {
    return power(a, mod - 2, mod);
}

long long solve(int n) {
    long long pow2n  = power(2, n, M);
    long long pow2n1 = power(2, n - 1, M);
    long long Nm1    = (pow2n - 1 + M) % M;    // 2^n - 1
    long long m_mod  = (pow2n1 - 1 + M) % M;   // 2^{n-1} - 1

    // Compute n! and C(2^n-1, n) = falling_factorial(Nm1, n) / n!
    long long fact_n = 1, falling_Nm1 = 1;
    for (int i = 0; i < n; i++) {
        fact_n = fact_n * ((i + 1) % M) % M;
        falling_Nm1 = falling_Nm1 % M * ((Nm1 - i % M + M) % M) % M;
    }
    long long inv_fact_n = modinv(fact_n, M);
    long long C_Nm1_n = falling_Nm1 % M * inv_fact_n % M;

    // Compute C(m, h) where m = 2^{n-1}-1, h = n/2
    int h = n / 2;
    long long fact_h = 1, falling_m = 1;
    for (int i = 0; i < h; i++) {
        fact_h = fact_h * ((i + 1) % M) % M;
        falling_m = falling_m % M * ((m_mod - i % M + M) % M) % M;
    }
    long long inv_fact_h = modinv(fact_h, M);
    long long C_m_h = falling_m % M * inv_fact_h % M;

    // E_n with sign
    int sign;
    if (n % 2 == 0) {
        sign = (h % 2 == 0) ? 1 : -1;
    } else {
        sign = (((n + 1) / 2) % 2 == 0) ? 1 : -1;
    }
    long long E_n_mod = (sign == 1) ? C_m_h : (M - C_m_h) % M;

    // W(n) = n! * (2^n - 1) * inv(2^n) * (C(2^n-1,n) - E_n) mod M
    long long inv_pow2n = modinv(pow2n, M);
    long long W = fact_n;
    W = W % M * (Nm1 % M) % M;
    W = W % M * (inv_pow2n % M) % M;
    W = W % M * ((C_Nm1_n - E_n_mod + M) % M) % M;
    return W;
}

int main() {
    ios_base::sync_with_stdio(false);

    // Verification
    struct { int n; long long expected; } tests[] = {
        {1, 1}, {2, 6}, {3, 168}, {5, 19764360}, {100, 384777056}
    };
    cout << "=== Verification ===" << endl;
    for (auto& t : tests) {
        long long w = solve(t.n);
        cout << "  W(" << t.n << ") mod M = " << w
             << "  expected " << t.expected
             << "  [" << (w == t.expected ? "OK" : "FAIL") << "]" << endl;
    }

    // Main computation
    cout << "\n=== Main computation ===" << endl;
    auto t0 = chrono::steady_clock::now();
    long long answer = solve(10000000);
    auto t1 = chrono::steady_clock::now();
    double elapsed = chrono::duration<double>(t1 - t0).count();

    cout << "  W(10,000,000) mod 10^9+7 = " << answer << endl;
    cout << "  Time: " << fixed << setprecision(2) << elapsed << "s" << endl;

    return 0;
}