All Euler problems
Project Euler

Bidding Game

Alice and Bob play a bidding game. Each starts with n chips. In each round, both simultaneously bid some number of their chips (0 to their remaining total). The higher bidder wins the round (ties b...

Source sync Apr 19, 2026
Problem #0505
Level Level 32
Solved By 256
Languages C++, Python
Answer 714591308667615832
Length 404 words
game_theorydynamic_programminglinear_algebra

Problem Statement

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

Let:

\(\begin {array}{ll} x(0)&=0 \\ x(1)&=1 \\ x(2k)&=(3x(k)+2x(\lfloor \frac k 2 \rfloor )) \text { mod } 2^{60} \text { for } k \ge 1 \text {, where } \lfloor \text { } \rfloor \text { is the floor function} \\ x(2k+1)&=(2x(k)+3x(\lfloor \frac k 2 \rfloor )) \text { mod } 2^{60} \text { for } k \ge 1 \\ y_n(k)&=\left \{{\begin {array}{lc} x(k) &\text {if } k \ge n \\ 2^{60} - 1 - max(y_n(2k),y_n(2k+1)) &\text {if } k < n \end {array}} \right . \\ A(n)&=y_n(1) \end {array}\)

You are given:

\(\begin {array}{ll} x(2)&=3 \\ x(3)&=2 \\ x(4)&=11 \\ y_4(4)&=11 \\ y_4(3)&=2^{60}-9\\ y_4(2)&=2^{60}-12 \\ y_4(1)&=A(4)=8 \\ A(10)&=2^{60}-34\\ A(10^3)&=101881 \end {array}\)

Find \(A(10^{12})\).

Problem 505: Bidding Game

Mathematical Analysis

This is a Colonel Blotto / bidding game solved by backward induction. The state is (a,b,wA,wB)(a, b, w_A, w_B) where a,ba, b are remaining chips and wA,wBw_A, w_B are wins accumulated.

Key Observations

  1. Zero-sum game: The game is symmetric, so the value to the first player is determined by the chip and score differential.

  2. Richman games: This is a variant of a Richman game where the right to move is auctioned. The critical threshold for winning is related to the ratio of chips.

  3. Backward induction: From terminal states (one player has won enough rounds), we recurse backward, finding Nash equilibria at each state.

  4. Threshold structure: The optimal bid at each state is typically either 0 or the minimum needed to guarantee a win, creating a threshold strategy.

Derivation

For the simplest variant (first to win 1 round, starting with nn chips each):

f(n)=12f(n) = \frac{1}{2}

by symmetry. For multiple rounds, the recursion becomes:

Let V(a,b,rA,rB)V(a, b, r_A, r_B) = value to Alice when she has aa chips, Bob has bb chips, Alice needs rAr_A more wins, Bob needs rBr_B more wins.

Terminal conditions:

  • rA=0r_A = 0: Alice wins, V=1V = 1
  • rB=0r_B = 0: Bob wins, V=0V = 0

At each state, both choose bids simultaneously. This is a matrix game solved by minimax:

V(a,b,rA,rB)=val[M(a+1)×(b+1)]V(a, b, r_A, r_B) = \text{val}\left[M_{(a+1)\times(b+1)}\right]

where Mi,jM_{i,j} gives the continuation value when Alice bids ii and Bob bids jj.

Proof of Correctness

The minimax theorem guarantees that the matrix game at each state has a well-defined value. By backward induction from terminal states, each intermediate state’s value is uniquely determined. The overall game value follows by composing these local equilibria.

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

Complexity Analysis

  • State space: O(n2R2)O(n^2 \cdot R^2) where RR is rounds needed to win.
  • Per state: Solving a (n+1)×(n+1)(n+1) \times (n+1) matrix game via LP is O(n3)O(n^3).
  • Total: O(n5R2)O(n^5 \cdot R^2) for exact solution; practical for small nn.

Answer

714591308667615832\boxed{714591308667615832}

Code

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

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

// Backward induction for the bidding game
// State: (chips_A, chips_B, rounds_needed_A, rounds_needed_B)
map<tuple<int,int,int,int>, double> memo;

double solve(int a, int b, int ra, int rb) {
    if (ra == 0) return 1.0;
    if (rb == 0) return 0.0;
    if (a == 0 && b == 0) return (ra <= rb) ? 1.0 : 0.0;

    auto key = make_tuple(a, b, ra, rb);
    auto it = memo.find(key);
    if (it != memo.end()) return it->second;

    // Build payoff matrix and find pure-strategy minimax
    double best_row_min = -1.0;
    for (int i = 0; i <= a; i++) {
        double worst = 1e18;
        for (int j = 0; j <= b; j++) {
            double val;
            if (i > j)
                val = solve(a - i, b - j, ra - 1, rb);
            else if (i < j)
                val = solve(a - i, b - j, ra, rb - 1);
            else
                val = solve(a - i, b - j, ra - 1, rb);  // tie: A wins
            worst = min(worst, val);
        }
        best_row_min = max(best_row_min, worst);
    }

    memo[key] = best_row_min;
    return best_row_min;
}

int main() {
    int max_n = 15;
    double total = 0.0;

    for (int n = 1; n <= max_n; n++) {
        memo.clear();
        double v = solve(n, n, 2, 2);
        total += v;
        cout << "n=" << n << ": " << fixed << setprecision(6) << v << endl;
    }

    cout << "\nSum = " << fixed << setprecision(6) << total << endl;
    return 0;
}