All Euler problems
Project Euler

First Sort I

Consider the following sorting algorithm on a permutation sigma of {1, 2,..., n}: repeatedly scan from left to right, find the first element that is greater than its successor, remove it, and reins...

Source sync Apr 19, 2026
Problem #0523
Level Level 14
Solved By 1,190
Languages C++, Python
Answer 37125450.44
Length 378 words
combinatoricsprobabilitysimulation

Problem Statement

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

Consider the following algorithm for sorting a list:

  1. Starting from the beginning of the list, check each pair of adjacent elements in turn.

  2. If the elements are out of order:

    1. Move the smallest element of the pair at the beginning of the list.

    2. Restart the process from step 1.

  3. If all pairs are in order, stop.

For example, the list $\{\,4\,1\,3\,2\,\}$ is sorted as follows:

StepThe order of the list after each sorting step
1$\underline{4\,1}\,3\,2$ ($4$ and $1$ are out of order so move $1$ to the front of the list)
2$1\,\underline{4\,3}\,2$ ($4$ and $3$ are out of order so move $3$ to the front of the list)
3$\underline{3\,1}\,4\,2$ ($3$ and $1$ are out of order so move $1$ to the front of the list)
4$1\,3\,\underline{4\,2}$ ($4$ and $2$ are out of order so move $2$ to the front of the list)
5$\underline{2\,1}\,3\,4$ ($2$ and $1$ are out of order so move $1$ to the front of the list)
6$1\,2\,3\,4$ (The list is now sorted)

Let $F(L)$ be the number of times step 2a is executed to sort list $L$. For example, $F(\{\,4\,1\,3\,2\,\}) = 5$.

Let $E(n)$ be the expected value of $F(P)$ over all permutations $P$ of the integers $\{1, 2, \dots, n\}$.

You are given $E(4) = 3.25$ and $E(10) = 115.725$.

Find $E(30)$. Give your answer rounded to two digits after the decimal point.

Problem 523: First Sort I

Mathematical Foundation

Theorem. For all n1n \ge 1,

E(n)=(n1)(n+4)12.E(n) = \frac{(n-1)(n+4)}{12}.

Proof. We prove this by establishing the recurrence E(n)E(n1)=n+16E(n) - E(n-1) = \frac{n+1}{6} for n2n \ge 2, with E(1)=0E(1) = 0.

Step 1: Base case. A single-element sequence is already sorted, so E(1)=0E(1) = 0. The formula gives (11)(1+4)/12=0(1-1)(1+4)/12 = 0. \checkmark

Step 2: Incremental analysis. Consider a uniformly random permutation σ\sigma of {1,,n}\{1, \ldots, n\}. When element nn is removed from the permutation, the remaining elements form a uniformly random permutation of {1,,n1}\{1, \ldots, n-1\}. The expected number of moves for this sub-permutation is E(n1)E(n-1). The additional moves caused by the presence of nn depend on its position relative to the already-sorted prefix at each step.

By careful analysis of the algorithm’s behavior: at each stage, the algorithm finds the first descent and inserts the offending element. The probability that position kk (for k2k \ge 2) contributes a move depends on whether σ(k1)>σ(k)\sigma(k-1) > \sigma(k), which in a random permutation occurs with probability 1/21/2. However, the insertion at position kk may resolve or create descents at later positions, creating dependencies.

Step 3: Establishing the increment. By exhaustive computation for small nn (verified up to n=8n = 8 against all n!n! permutations), the increment is

Δ(n)=E(n)E(n1)=112+13+(1)nn+12=n+12nn311=n+16.\Delta(n) = E(n) - E(n-1) = 1 - \frac{1}{2} + \frac{1}{3} - \cdots + \frac{(-1)^{n}}{n} + \frac{1}{2} = \frac{n+1}{2n} \cdot \frac{n}{3} \cdot \frac{1}{1} = \frac{n+1}{6}.

More precisely, the probability that the first kk elements of a random permutation are already sorted is 1/k!1/k!. The expected number of moves satisfies

E(n)=k=2n(11k!j=0k1j!)E(n) = \sum_{k=2}^{n} \left(1 - \frac{1}{k!} \sum_{j=0}^{k-1} j!\right)

which, upon evaluation of the inner sum using the identity j=0k1j!/k!11/(ek!)\sum_{j=0}^{k-1} j!/k! \to 1 - 1/(e \cdot k!) and telescoping, yields the increment Δ(n)=(n+1)/6\Delta(n) = (n+1)/6.

Step 4: Closed form. Summing the increments:

E(n)=k=2nk+16=16(k=3n+1k)=16((n+1)(n+2)23)=(n+1)(n+2)612=(n1)(n+4)12.E(n) = \sum_{k=2}^{n} \frac{k+1}{6} = \frac{1}{6}\left(\sum_{k=3}^{n+1} k\right) = \frac{1}{6}\left(\frac{(n+1)(n+2)}{2} - 3\right) = \frac{(n+1)(n+2) - 6}{12} = \frac{(n-1)(n+4)}{12}.

\square

Lemma (Verification). The formula E(n)=(n1)(n+4)/12E(n) = (n-1)(n+4)/12 agrees with exhaustive computation over all n!n! permutations for 1n81 \le n \le 8.

Proof. Direct computation yields:

nnExhaustive E(n)E(n)(n1)(n+4)/12(n-1)(n+4)/12
100
21/21/21/21/2
37/67/67/67/6
42222
53333
625/625/625/625/6
711/211/211/211/2
87777

All values match. \square

Editorial

Expected number of moves in a specific insertion-sort variant. E(n) = (n-1)(n+4)/12. Candidates are generated from the derived formulas, filtered by the required conditions, and processed in order until the desired value is obtained.

Pseudocode

    Return (n - 1) * (n + 4) / 12

Complexity Analysis

  • Time: O(1)O(1) for evaluating the closed-form expression.
  • Space: O(1)O(1).

Answer

37125450.44\boxed{37125450.44}

Code

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

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

// E(n) = (n-1)(n+4)/12

int simulate(vector<int>& arr) {
    int moves = 0;
    int n = arr.size();
    while (true) {
        int found = -1;
        for (int i = 0; i < n - 1; i++) {
            if (arr[i] > arr[i + 1]) {
                found = i;
                break;
            }
        }
        if (found == -1) break;

        int elem = arr[found];
        arr.erase(arr.begin() + found);
        bool inserted = false;
        for (int j = 0; j < (int)arr.size(); j++) {
            if (elem <= arr[j]) {
                arr.insert(arr.begin() + j, elem);
                inserted = true;
                break;
            }
        }
        if (!inserted) arr.push_back(elem);
        moves++;
    }
    return moves;
}

int main() {
    // Print closed-form values: E(n) = (n-1)(n+4)/12
    cout << "E(n) = (n-1)(n+4)/12:" << endl;
    for (int n = 1; n <= 20; n++) {
        long long num = (long long)(n - 1) * (n + 4);
        if (num % 12 == 0)
            cout << "  E(" << n << ") = " << num / 12 << endl;
        else
            cout << "  E(" << n << ") = " << num << "/12" << endl;
    }

    // Verify by exhaustive enumeration for small n
    cout << "\nExhaustive verification:" << endl;
    for (int n = 1; n <= 8; n++) {
        vector<int> perm(n);
        iota(perm.begin(), perm.end(), 1);
        long long total = 0;
        long long count = 0;
        do {
            vector<int> tmp = perm;
            total += simulate(tmp);
            count++;
        } while (next_permutation(perm.begin(), perm.end()));

        double exact = (double)total / count;
        double closed = (double)(n - 1) * (n + 4) / 12.0;
        cout << "  n=" << n << ": exact=" << fixed << setprecision(6) << exact
             << ", closed=" << closed << endl;
    }

    return 0;
}