All Euler problems
Project Euler

Lexicographic Permutations

A permutation is an ordered arrangement of objects. The lexicographic permutations of {0, 1, 2} are: 012, 021, 102, 120, 201, 210. What is the millionth lexicographic permutation of the digits {0,...

Source sync Apr 19, 2026
Problem #0024
Level Level 00
Solved By 125,791
Languages C++, Python
Answer 2783915460
Length 646 words
combinatoricsconstructivemodular_arithmetic

Problem Statement

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

A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are: $$012 \quad 021 \quad 102 \quad 120 \quad 201 \quad 210$$ What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?

Problem 24: Lexicographic Permutations

Mathematical Development

Definitions

Definition 1 (Factorial Number System). The factoradic (or factorial number system) represents a non-negative integer kk as

k=i=1mdii!,k = \sum_{i=1}^{m} d_i \cdot i!,

where the digits satisfy 0dii0 \leq d_i \leq i for each 1im1 \leq i \leq m.

Definition 2 (Lehmer Code). Given a permutation π\pi of {0,1,,n1}\{0, 1, \ldots, n-1\}, its Lehmer code is the sequence (l0,l1,,ln1)(l_0, l_1, \ldots, l_{n-1}) where li={j>i:π(j)<π(i)}l_i = |\{j > i : \pi(j) < \pi(i)\}| counts elements to the right of position ii that are smaller than π(i)\pi(i).

Theorems and Proofs

Theorem 1 (Factoradic Uniqueness). Every non-negative integer kk with 0k<n!0 \leq k < n! has a unique factoradic representation (dn1,dn2,,d1)(d_{n-1}, d_{n-2}, \ldots, d_1) satisfying 0dii0 \leq d_i \leq i for each ii.

Proof. We proceed by strong induction on nn.

Base case (n=1n = 1): The only value is k=0k = 0, represented by the empty sequence.

Inductive step: Assume the claim holds for all factorials up to (n1)!(n-1)!. Given 0k<n!0 \leq k < n!, apply the division algorithm: k=dn1(n1)!+rk = d_{n-1} \cdot (n-1)! + r, where dn1=k/(n1)!d_{n-1} = \lfloor k/(n-1)! \rfloor and r=kmod(n1)!r = k \bmod (n-1)!. Since k<n(n1)!k < n \cdot (n-1)!, we have 0dn1n10 \leq d_{n-1} \leq n - 1. Since 0r<(n1)!0 \leq r < (n-1)!, the inductive hypothesis yields a unique representation of rr as (dn2,,d1)(d_{n-2}, \ldots, d_1). Uniqueness of the full representation follows from the uniqueness of quotient and remainder in the division algorithm. \square

Theorem 2 (Lehmer Code Bijection). There is a bijection between {0,1,,n!1}\{0, 1, \ldots, n!-1\} and the permutations of nn elements in lexicographic order, mediated by the factoradic representation. Specifically, if k=dn1(n1)!+dn2(n2)!++d11!k = d_{n-1}(n-1)! + d_{n-2}(n-2)! + \cdots + d_1 \cdot 1!, then the kk-th permutation (0-indexed) is constructed by: at step ii (i=0,1,,n1i = 0, 1, \ldots, n-1), select the element of rank dn1id_{n-1-i} among the remaining elements.

Proof. By induction on nn.

Base case (n=1n = 1): The single permutation corresponds to k=0k = 0.

Inductive step: Partition the n!n! permutations into nn blocks of size (n1)!(n-1)! each, where block jj contains all permutations beginning with the jj-th smallest element (0-indexed). The permutation at global index kk lies in block dn1=k/(n1)!d_{n-1} = \lfloor k/(n-1)! \rfloor, and has local index r=kmod(n1)!r = k \bmod (n-1)! within that block. By the inductive hypothesis, the remaining n1n-1 positions are determined by the factoradic digits (dn2,,d1)(d_{n-2}, \ldots, d_1) applied to the remaining n1n-1 elements. Since the block structure respects lexicographic order and the inductive step preserves it, the full construction produces the kk-th permutation. \square

Lemma 1 (Feasibility). The millionth permutation corresponds to 0-based index k=999,999k = 999{,}999, and k<10!=3,628,800k < 10! = 3{,}628{,}800, so the factoradic representation exists with n=10n = 10.

Proof. Immediate from 999,999<3,628,800=10!999{,}999 < 3{,}628{,}800 = 10!. \square

Computation

Applying Theorem 2 with k=999,999k = 999{,}999 and n=10n = 10:

Step iikk(9i)!(9-i)!d9i=k/(9i)!d_{9-i} = \lfloor k / (9-i)! \rfloorRemainderAvailable digitsSelected
09999993628802274239{0,1,2,3,4,5,6,7,8,9}2
127423940320632319{0,1,3,4,5,6,7,8,9}7
232319504062079{0,1,3,4,5,6,8,9}8
320797202639{0,1,3,4,5,6,9}3
4639120539{0,1,4,5,6,9}9
53924115{0,1,4,5,6}1
615623{0,4,5,6}5
73211{0,4,6}4
81110{0,6}6
90100{0}0

Editorial

We construct the required permutation directly from the factoradic representation of k1k-1. At each position we compute the relevant factorial block size, choose the corresponding index among the remaining digits, append that digit to the answer, and remove it from the available set. This is sufficient because lexicographic permutations are partitioned into equal factorial-sized blocks at each step.

Pseudocode

Algorithm: Lexicographic Permutation by Factoradic Selection
Require: An ordered digit set D and an index k ≥ 1.
Ensure: The k-th permutation of D in lexicographic order.
1: Set k' ← k - 1 and let R be the ordered list of available digits.
2: For each position from most significant to least significant do:
3:     Let m be the number of digits that will remain after this position, and compute q ← floor(k' / m!).
4:     Append the q-th element of R to the output, remove it from R, and replace k' ← k' mod m!.
5: Return the constructed permutation.

Complexity Analysis

Proposition. Algorithm KthPermutation runs in O(n2)O(n^2) time and O(n)O(n) space.

Proof. The main loop iterates nn times. In each iteration, the dominant cost is the removal of an element from the list available, which takes O(n)O(n) time with an array-based list (shifting subsequent elements). All other operations (factorial lookup, integer division, modular reduction) are O(1)O(1) per iteration. Total: O(n)×O(n)=O(n2)O(n) \times O(n) = O(n^2).

Space consists of the available list and result, each of size O(n)O(n).

Remark. Using a balanced order-statistic tree (e.g., an augmented AVL or red-black tree), the select-and-delete operation can be performed in O(logn)O(\log n) per step, reducing the total time to O(nlogn)O(n \log n). \square

Answer

2783915460\boxed{2783915460}

Code

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

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

int main() {
    const int n = 10;
    int k = 1000000 - 1;

    vector<int> fact(n, 1);
    for (int i = 1; i < n; i++)
        fact[i] = fact[i - 1] * i;

    vector<int> digits = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    string result;
    for (int i = 0; i < n; i++) {
        int f = fact[n - 1 - i];
        int idx = k / f;
        k %= f;
        result += to_string(digits[idx]);
        digits.erase(digits.begin() + idx);
    }

    cout << result << endl;
    return 0;
}