IOI 2001 - Score
Problem Statement Summary Given a decimal number as a string of N digits and a budget of K adjacent swaps, find the maximum and minimum numbers obtainable. Leading zeros are not permitted (except for the number 0 itse...
Source-first archive entry
This page is built from the copied files in competitive_programming/ioi/2001/score. Edit
competitive_programming/ioi/2001/score/solution.tex to update the written solution and
competitive_programming/ioi/2001/score/solution.cpp to update the implementation.
The website does not replace those files with hand-maintained HTML. It reads the copied source tree during the build and exposes the exact files below.
Problem Statement
This archive entry does not include a standalone statement file or a dedicated statement section in solution.tex.
The statement is not mirrored as a separate asset in this archive. The editorial and source files remain available below.
Editorial
Rendered from the copied solution.tex file. The original TeX source remains
available below.
Problem Statement Summary
Given a decimal number as a string of $N$ digits and a budget of $K$ adjacent swaps, find the maximum and minimum numbers obtainable. Leading zeros are not permitted (except for the number 0 itself).
Solution: Greedy Selection Sort
Maximizing
Process positions left to right. At position $i$, locate the largest digit in the range $[i, \min(i+K, N-1)]$ (breaking ties by choosing the leftmost occurrence to minimize swaps). Bubble it to position $i$ by swapping with its left neighbor repeatedly, deducting the number of swaps used from $K$.
Lemma.
The greedy strategy is optimal for maximization.
Proof.
At each step we place the largest reachable digit into the leftmost unfilled position. Any other choice yields a lexicographically smaller result, because the first position where the two results differ will have a smaller digit in the non-greedy solution.
Minimizing
The same strategy applies, but we select the smallest digit. For position 0, we skip digit `0' to avoid leading zeros---we select the smallest non-zero digit reachable within $K$ swaps.
Edge Case
If the string is all zeros (representing the number 0), no leading-zero avoidance is needed.
C++ Implementation
#include <bits/stdc++.h>
using namespace std;
string maximize(string s, int K) {
int n = s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++)
if (s[j] > s[bestPos])
bestPos = j;
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
string minimize(string s, int K) {
int n = s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (i == 0) {
// Avoid leading zero
if (s[j] == '0') continue;
if (s[bestPos] == '0' || s[j] < s[bestPos])
bestPos = j;
} else {
if (s[j] < s[bestPos])
bestPos = j;
}
}
// If all reachable digits for position 0 are '0', skip
if (i == 0 && s[bestPos] == '0') continue;
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string S;
int K;
cin >> S >> K;
cout << minimize(S, K) << "\n";
cout << maximize(S, K) << "\n";
return 0;
}
Complexity Analysis
Time: $O(N \cdot \min(N, K))$. For each of $N$ positions, we scan at most $\min(K, N)$ positions ahead. The total number of swaps across all iterations is at most $K$.
Space: $O(N)$.
Code
Exact copied C++ implementation from solution.cpp.
// IOI 2001 - Score
// Given a decimal number string and K allowed adjacent swaps,
// find the maximum and minimum achievable numbers.
// Greedy: for each position, find best digit within swap range and bubble it in.
// Minimizing avoids leading zeros.
// Complexity: O(N * min(N, K)) time, O(N) space.
#include <bits/stdc++.h>
using namespace std;
string maximize(string s, int K) {
int n = (int)s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
// Find position of the maximum digit in s[i..min(i+K, n-1)]
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (s[j] > s[bestPos]) {
bestPos = j;
}
}
// Bubble s[bestPos] to position i
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
string minimize(string s, int K) {
int n = (int)s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (i == 0) {
// Avoid leading zero: skip '0' candidates for first position
if (s[j] == '0') continue;
if (s[j] < s[bestPos] || s[bestPos] == '0') {
bestPos = j;
}
} else {
if (s[j] < s[bestPos]) {
bestPos = j;
}
}
}
// Bubble s[bestPos] to position i
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string S;
int K;
cin >> S >> K;
// Edge case: single digit
if (S.size() <= 1) {
cout << S << "\n" << S << "\n";
return 0;
}
string maxResult = maximize(S, K);
string minResult = minimize(S, K);
cout << minResult << "\n";
cout << maxResult << "\n";
return 0;
}
Source Files
Exact copied source-of-truth files. Edit solution.tex for the write-up and solution.cpp for the implementation.
\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,amssymb,amsthm}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}
\newtheorem{theorem}{Theorem}
\newtheorem{lemma}[theorem]{Lemma}
\lstset{
language=C++,
basicstyle=\ttfamily\small,
keywordstyle=\color{blue}\bfseries,
commentstyle=\color{green!60!black},
stringstyle=\color{red},
numbers=left,
numberstyle=\tiny\color{gray},
breaklines=true,
frame=single,
tabsize=4,
showstringspaces=false
}
\title{IOI 2001 -- Score}
\author{Solution}
\date{}
\begin{document}
\maketitle
\section{Problem Statement Summary}
Given a decimal number as a string of $N$ digits and a budget of $K$
adjacent swaps, find the maximum and minimum numbers obtainable.
Leading zeros are not permitted (except for the number 0 itself).
\section{Solution: Greedy Selection Sort}
\subsection{Maximizing}
Process positions left to right. At position $i$, locate the largest
digit in the range $[i, \min(i+K, N-1)]$ (breaking ties by choosing
the leftmost occurrence to minimize swaps). Bubble it to position $i$
by swapping with its left neighbor repeatedly, deducting the number of
swaps used from $K$.
\begin{lemma}
The greedy strategy is optimal for maximization.
\end{lemma}
\begin{proof}
At each step we place the largest reachable digit into the
leftmost unfilled position. Any other choice yields a lexicographically
smaller result, because the first position where the two results differ
will have a smaller digit in the non-greedy solution.
\end{proof}
\subsection{Minimizing}
The same strategy applies, but we select the \emph{smallest} digit.
For position 0, we skip digit `0' to avoid leading zeros---we select
the smallest \emph{non-zero} digit reachable within $K$ swaps.
\subsection{Edge Case}
If the string is all zeros (representing the number 0), no leading-zero
avoidance is needed.
\section{C++ Implementation}
\begin{lstlisting}
#include <bits/stdc++.h>
using namespace std;
string maximize(string s, int K) {
int n = s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++)
if (s[j] > s[bestPos])
bestPos = j;
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
string minimize(string s, int K) {
int n = s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (i == 0) {
// Avoid leading zero
if (s[j] == '0') continue;
if (s[bestPos] == '0' || s[j] < s[bestPos])
bestPos = j;
} else {
if (s[j] < s[bestPos])
bestPos = j;
}
}
// If all reachable digits for position 0 are '0', skip
if (i == 0 && s[bestPos] == '0') continue;
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string S;
int K;
cin >> S >> K;
cout << minimize(S, K) << "\n";
cout << maximize(S, K) << "\n";
return 0;
}
\end{lstlisting}
\section{Complexity Analysis}
\begin{itemize}
\item \textbf{Time:} $O(N \cdot \min(N, K))$. For each of $N$
positions, we scan at most $\min(K, N)$ positions ahead.
The total number of swaps across all iterations is at most $K$.
\item \textbf{Space:} $O(N)$.
\end{itemize}
\end{document}
// IOI 2001 - Score
// Given a decimal number string and K allowed adjacent swaps,
// find the maximum and minimum achievable numbers.
// Greedy: for each position, find best digit within swap range and bubble it in.
// Minimizing avoids leading zeros.
// Complexity: O(N * min(N, K)) time, O(N) space.
#include <bits/stdc++.h>
using namespace std;
string maximize(string s, int K) {
int n = (int)s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
// Find position of the maximum digit in s[i..min(i+K, n-1)]
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (s[j] > s[bestPos]) {
bestPos = j;
}
}
// Bubble s[bestPos] to position i
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
string minimize(string s, int K) {
int n = (int)s.size();
for (int i = 0; i < n - 1 && K > 0; i++) {
int bestPos = i;
for (int j = i + 1; j < n && j - i <= K; j++) {
if (i == 0) {
// Avoid leading zero: skip '0' candidates for first position
if (s[j] == '0') continue;
if (s[j] < s[bestPos] || s[bestPos] == '0') {
bestPos = j;
}
} else {
if (s[j] < s[bestPos]) {
bestPos = j;
}
}
}
// Bubble s[bestPos] to position i
for (int j = bestPos; j > i; j--) {
swap(s[j], s[j - 1]);
K--;
}
}
return s;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string S;
int K;
cin >> S >> K;
// Edge case: single digit
if (S.size() <= 1) {
cout << S << "\n" << S << "\n";
return 0;
}
string maxResult = maximize(S, K);
string minResult = minimize(S, K);
cout << minResult << "\n";
cout << maxResult << "\n";
return 0;
}