IOI 1996
IOI 1996

Sorting a Three-Valued Sequence

Problem Statement Given a sequence of n integers, each being 1, 2, or 3, sort the sequence in non-decreasing order using the minimum number of swaps. Each swap exchanges exactly two elements at arbitrary positions.: 1...

Updated May 21, 2026
Track IOI
Year 1996
Statement Rendered from TeX
TeXC++Rendered statement

Problem Statement

Rendered from the "Problem Statement" section in the LaTeX write-up.

Given a sequence of $n$ integers, each being 1, 2, or 3, sort the sequence in non-decreasing order using the minimum number of swaps. Each swap exchanges exactly two elements at arbitrary positions.

Constraints: $1 \le n \le 1000$.

Editorial

The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.

Solution Approach

Zones and Misplacement Counts

In the sorted sequence, we know exactly which positions hold each value:

  • Zone 1 (positions $1 \ldots n_1$): should contain all 1s.

  • Zone 2 (positions $n_1{+}1 \ldots n_1{+}n_2$): should contain all 2s.

  • Zone 3 (positions $n_1{+}n_2{+}1 \ldots n$): should contain all 3s.

  • Here $n_v = |\{i : a_i = v\}|$ for $v \in \{1,2,3\}$.

    Define $c_{ij}$ as the number of positions in zone $i$ that currently hold value $j$. For example, $c_{12}$ counts the 2s sitting in positions meant for 1s.

Two-Cycles and Three-Cycles

A two-cycle is a pair of misplaced elements that can fix each other with one swap. For instance, a 2 in zone 1 paired with a 1 in zone 2 can be swapped, fixing both. The number of such swaps between zones $i$ and $j$ is $\min(c_{ij}, c_{ji})$.

After exhausting all two-cycles, the remaining misplaced elements form three-cycles, each involving one element from each zone (e.g., a 2 in zone 1, a 3 in zone 2, and a 1 in zone 3). Each three-cycle requires 2 swaps.

Formula

After performing two-cycle swaps, the residual counts satisfy $c_{12}' = c_{23}' = c_{31}'$ (one rotation direction) and $c_{13}' = c_{32}' = c_{21}'$ (the other direction), since the surplus must balance across all three zones. The total number of swaps is: \[ \text{swaps} = \underbrace{\min(c_{12}, c_{21}) + \min(c_{13}, c_{31}) + \min(c_{23}, c_{32})}_{\text{two-cycles}} + \underbrace{2 \cdot (c_{12}' + c_{13}')}_{\text{three-cycles}}. \]

Proof (Proof of optimality).

Each swap fixes at most 2 misplaced elements. Two-cycles achieve this maximum. Three-cycles require 2 swaps for 3 misplacements (the best possible since 1 swap can fix at most 2). Thus no strategy can use fewer swaps.

C++ Solution

#include <cstdio>
#include <algorithm>
using namespace std;

int main() {
    int n;
    scanf("%d", &n);

    int a[1001];
    int cnt[4] = {}; // cnt[v] = count of value v

    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        cnt[a[i]]++;
    }

    // Zone boundaries (0-indexed)
    // Zone 1: [0, cnt[1])
    // Zone 2: [cnt[1], cnt[1]+cnt[2])
    // Zone 3: [cnt[1]+cnt[2], n)

    // c[i][j] = count of value j in zone i
    int c[4][4] = {};
    for (int i = 0; i < n; i++) {
        int zone;
        if (i < cnt[1]) zone = 1;
        else if (i < cnt[1] + cnt[2]) zone = 2;
        else zone = 3;
        c[zone][a[i]]++;
    }

    // Two-cycle swaps
    int swaps = 0;
    int two12 = min(c[1][2], c[2][1]);
    int two13 = min(c[1][3], c[3][1]);
    int two23 = min(c[2][3], c[3][2]);
    swaps += two12 + two13 + two23;

    // Subtract two-cycle contributions
    c[1][2] -= two12; c[2][1] -= two12;
    c[1][3] -= two13; c[3][1] -= two13;
    c[2][3] -= two23; c[3][2] -= two23;

    // Remaining misplacements form three-cycles, each needing 2 swaps
    swaps += 2 * (c[1][2] + c[1][3]);

    printf("%d\n", swaps);
    return 0;
}

Complexity Analysis

  • Time complexity: $O(n)$. One pass to count values and compute zone membership; the rest is $O(1)$ arithmetic.

  • Space complexity: $O(n)$ for the input array. The counting arrays use $O(1)$ additional space.

Code

C++ solution used for this page.

C++

Clean code view with a raw-file link when you want the original source.

Raw file
// IOI 1996 - Sorting a Three-Valued Sequence
// Count misplacements between zones, resolve 2-cycles then 3-cycles
// Time: O(n), Space: O(n)
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    scanf("%d", &n);

    int a[1001];
    int cnt[4] = {}; // cnt[v] = count of value v

    for (int i = 0; i < n; i++) {
        scanf("%d", &a[i]);
        cnt[a[i]]++;
    }

    // Zone boundaries (0-indexed)
    // Zone 1: [0, cnt[1])
    // Zone 2: [cnt[1], cnt[1]+cnt[2])
    // Zone 3: [cnt[1]+cnt[2], n)

    // c[i][j] = count of value j in zone i
    int c[4][4] = {};
    for (int i = 0; i < n; i++) {
        int zone;
        if (i < cnt[1]) zone = 1;
        else if (i < cnt[1] + cnt[2]) zone = 2;
        else zone = 3;
        c[zone][a[i]]++;
    }

    // Two-cycle swaps
    int swaps = 0;
    int two12 = min(c[1][2], c[2][1]);
    int two13 = min(c[1][3], c[3][1]);
    int two23 = min(c[2][3], c[3][2]);
    swaps += two12 + two13 + two23;

    // Remaining after two-cycles
    c[1][2] -= two12; c[2][1] -= two12;
    c[1][3] -= two13; c[3][1] -= two13;
    c[2][3] -= two23; c[3][2] -= two23;

    // Remaining misplacements form three-cycles, each needs 2 swaps
    swaps += 2 * (c[1][2] + c[1][3]);

    printf("%d\n", swaps);
    return 0;
}

Source Files and Assets

Raw files are still available here when you want the original TeX, C++, or statement assets.

Show raw files