All Euler problems
Project Euler

Scoring Probabilities

Barbara shoots from distances x = 1, 2,..., 50 with success probability p_x = 1 - x/q for a real constant q > 50. The probability of scoring exactly 20 points (out of 50 shots) is exactly 2%. Find...

Source sync Apr 19, 2026
Problem #0286
Level Level 09
Solved By 2,490
Languages C++, Python
Answer 52.6494571953
Length 325 words
dynamic_programmingprobabilityalgebra

Problem Statement

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

Barbara is a mathematician and a basketball player. She has found that the probability of scoring a point when shooting from a distance \(x\) is exactly \((1 - x / q)\), where \(q\) is a real constant greater than \(50\).

During each practice run, she takes shots from distances \(x = 1, x = 2, \dots , x = 50\) and, according to her records, she has precisely a \(2\%\) chance to score a total of exactly \(20\) points.

Find \(q\) and give your answer rounded to \(10\) decimal places.

Problem 286: Scoring Probabilities

Mathematical Foundation

Theorem (DP Characterization). Let dp[i][j]\text{dp}[i][j] denote the probability of scoring exactly jj points in the first ii shots. Then dp[0][0]=1\text{dp}[0][0] = 1, dp[0][j]=0\text{dp}[0][j] = 0 for j>0j > 0, and

dp[i][j]=dp[i1][j]iq+dp[i1][j1](1iq).\text{dp}[i][j] = \text{dp}[i-1][j] \cdot \frac{i}{q} + \text{dp}[i-1][j-1] \cdot \left(1 - \frac{i}{q}\right).

The function g(q)=dp[50][20]g(q) = \text{dp}[50][20] is a polynomial of degree 50 in 1/q1/q.

Proof. Shot ii is an independent Bernoulli trial with success probability 1i/q1 - i/q and failure probability i/qi/q. The recurrence follows from conditioning on the outcome of shot ii. Since all 50 shots are independent with distinct success probabilities, the probability of exactly 20 successes is an elementary symmetric function of the success/failure probabilities, hence a rational function (in fact polynomial in 1/q1/q) of degree 50. \quad\square

Theorem (Existence and Uniqueness of Root). The equation g(q)=0.02g(q) = 0.02 has a unique solution in (50,)(50, \infty).

Proof. At q=50q = 50: p50=0p_{50} = 0, and the expected number of successes is k=149(1k/50)=24.5\sum_{k=1}^{49}(1 - k/50) = 24.5. At qq \to \infty: all pk1p_k \to 1, so the probability mass concentrates at 50, making P(X=20)0P(X = 20) \to 0.

For qq slightly above 50, the mean is near 24.5 and the distribution is spread, giving P(X=20)P(X=20) a value well above 0.02. As qq increases, the mean shifts right and eventually P(X=20)P(X=20) decreases below 0.02. By continuity and the intermediate value theorem, at least one root exists.

To show uniqueness: for large enough qq the distribution becomes sharply concentrated near 50, so g(q)<0.02g(q) < 0.02 for all sufficiently large qq. In the transition region, one can verify numerically (or by analyzing the log-concavity of the Poisson-binomial distribution) that gg crosses the level 0.02 exactly once from above. \quad\square

Lemma (Bisection Convergence). The bisection method on [qlo,qhi][q_{\text{lo}}, q_{\text{hi}}] with g(qlo)>0.02>g(qhi)g(q_{\text{lo}}) > 0.02 > g(q_{\text{hi}}) converges to dd correct decimal places in dlog210+log2(qhiqlo)\lceil d \cdot \log_2 10 + \log_2(q_{\text{hi}} - q_{\text{lo}})\rceil iterations.

Proof. Standard bisection halves the interval at each step. \quad\square

Editorial

02, where shot k scores with probability (1 - k/q). We else. 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

    lo = 50.0
    hi = 100.0
    for iter = 1 to 200: // ensures > 50 digits of precision
        mid = (lo + hi) / 2
        If dp_eval(mid) > 0.02 then
            lo = mid
        else:
            hi = mid
    Return round(lo, 10)

    dp = array[0..50] initialized to 0
    dp[0] = 1.0
    For i from 1 to 50:
        p_hit = 1 - i/q
        p_miss = i/q
        for j = min(i, 20) downto 1:
            dp[j] = dp[j] * p_miss + dp[j-1] * p_hit
        dp[0] = dp[0] * p_miss
    Return dp[20]

Complexity Analysis

  • Time: O(Int)O(I \cdot n \cdot t) where I200I \approx 200 bisection iterations, n=50n = 50 shots, t=20t = 20 target score. Total: O(2005020)=O(200000)O(200 \cdot 50 \cdot 20) = O(200000).
  • Space: O(t)=O(20)O(t) = O(20) using a rolling 1D DP array.

Answer

52.6494571953\boxed{52.6494571953}

Code

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

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

// Compute P(exactly 20 scores in 50 shots) given q
double compute(double q) {
    // dp[j] = probability of exactly j scores so far
    vector<double> dp(21, 0.0);
    dp[0] = 1.0;
    for (int i = 1; i <= 50; i++) {
        double p_score = 1.0 - (double)i / q;  // probability of scoring shot i
        double p_miss = (double)i / q;
        // Update in reverse to avoid overwriting
        for (int j = min(i, 20); j >= 1; j--) {
            dp[j] = dp[j] * p_miss + dp[j - 1] * p_score;
        }
        dp[0] *= p_miss;
    }
    return dp[20];
}

int main() {
    double lo = 50.0, hi = 100.0;
    double target = 0.02;

    // Binary search for q
    for (int iter = 0; iter < 200; iter++) {
        double mid = (lo + hi) / 2.0;
        double val = compute(mid);
        if (val > target) {
            lo = mid;  // need larger q to decrease P(X=20)
        } else {
            hi = mid;
        }
    }

    printf("%.10f\n", (lo + hi) / 2.0);
    return 0;
}