All IOI entries
Competitive Programming

IOI 2002 - Frog

Problem Statement Summary N stones (N 10^5) are arranged in a circle, numbered 1 through N. A frog sits on stone 1. Each jump, the frog advances exactly D stones clockwise. After each jump, the stone the frog lands on...

Source sync Apr 19, 2026
Track IOI
Year 2002
Files TeX and C++
Folder competitive_programming/ioi/2002/frog
IOI2002TeXC++

Source-first archive entry

This page is built from the copied files in competitive_programming/ioi/2002/frog. Edit competitive_programming/ioi/2002/frog/solution.tex to update the written solution and competitive_programming/ioi/2002/frog/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

$N$ stones ($N \le 10^5$) are arranged in a circle, numbered $1$ through $N$. A frog sits on stone 1. Each jump, the frog advances exactly $D$ stones clockwise. After each jump, the stone the frog lands on is removed. The frog then adjusts to the nearest remaining stone (with specific tie-breaking rules).

Simulate the process and output the order in which stones are removed.

Solution: Fenwick Tree for Order Statistics

Key Idea

Maintain the set of remaining stones in a Fenwick tree, where $\text{bit}[i] = 1$ if stone $i$ is present and $0$ otherwise. This supports:

  • Finding the $k$-th remaining stone in $O(\log N)$ (binary lifting on the BIT).

  • Removing a stone in $O(\log N)$.

Circular Jump

If there are $R$ stones remaining and the frog is at rank $r$ (1-indexed among remaining stones), after removing the current stone ($R$ becomes $R - 1$), the stones after the removed one shift down in rank. The frog's new target rank is: \[ r' = \bigl((r - 1) + (D - 1)\bigr) \bmod R' + 1 \qquad\text{where } R' = R - 1. \] This accounts for the fact that the current stone is removed before jumping.

C++ Implementation

#include <bits/stdc++.h>
using namespace std;

struct BIT {
    int n;
    vector<int> tree;

    BIT(int n) : n(n), tree(n + 1, 0) {}

    void update(int i, int val) {
        for (; i <= n; i += i & (-i))
            tree[i] += val;
    }

    int query(int i) {
        int s = 0;
        for (; i > 0; i -= i & (-i))
            s += tree[i];
        return s;
    }

    // Find the k-th element (1-indexed) via binary lifting.
    int kth(int k) {
        int pos = 0;
        for (int bm = 1 << __lg(n); bm > 0; bm >>= 1) {
            int next = pos + bm;
            if (next <= n && tree[next] < k) {
                k -= tree[next];
                pos = next;
            }
        }
        return pos + 1;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, D;
    cin >> N >> D;

    BIT bit(N);
    for (int i = 1; i <= N; i++)
        bit.update(i, 1);

    int remaining = N;
    int curRank = 1; // rank of stone 1 among remaining stones

    for (int step = 0; step < N; step++) {
        int stone = bit.kth(curRank);
        cout << stone << "\n";

        bit.update(stone, -1);
        remaining--;

        if (remaining == 0) break;

        // After removing the stone at curRank, compute new rank.
        // Ranks >= curRank shift down by 1, so the "next" stone
        // is now at curRank (if it exists). We advance D-1 more.
        curRank = ((curRank - 1 + D - 1) % remaining) + 1;
    }

    return 0;
}

Complexity Analysis

  • Time: $O(N \log N)$. Each of the $N$ steps performs one $k$-th element query ($O(\log N)$) and one update ($O(\log N)$).

  • Space: $O(N)$.

Code

Exact copied C++ implementation from solution.cpp.

C++ competitive_programming/ioi/2002/frog/solution.cpp

Exact copied implementation source.

Raw file
// IOI 2002 - Frog
// N stones in a circle, frog on stone 1. Frog jumps D positions clockwise,
// removing the departure stone after each jump.
// Uses a Fenwick tree for O(log N) k-th element queries and updates.
// Complexity: O(N log N) time, O(N) space.

#include <bits/stdc++.h>
using namespace std;

struct BIT {
    int n;
    vector<int> tree;

    BIT(int n) : n(n), tree(n + 1, 0) {}

    void update(int i, int val) {
        for (; i <= n; i += i & (-i))
            tree[i] += val;
    }

    int query(int i) {
        int s = 0;
        for (; i > 0; i -= i & (-i))
            s += tree[i];
        return s;
    }

    // Find the k-th element (1-indexed) using binary lifting on the BIT
    int kth(int k) {
        int pos = 0;
        int bitMask = 1;
        while (bitMask <= n) bitMask <<= 1;
        bitMask >>= 1;

        for (; bitMask > 0; bitMask >>= 1) {
            int next = pos + bitMask;
            if (next <= n && tree[next] < k) {
                k -= tree[next];
                pos = next;
            }
        }
        return pos + 1;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, D;
    cin >> N >> D;

    BIT bit(N);
    for (int i = 1; i <= N; i++) {
        bit.update(i, 1);
    }

    int remaining = N;
    int currentRank = 1; // rank of current stone among remaining stones

    vector<int> order;
    order.reserve(N);

    while (remaining > 0) {
        int stone = bit.kth(currentRank);
        order.push_back(stone);

        // Remove current stone
        bit.update(stone, -1);
        remaining--;

        if (remaining == 0) break;

        // After removing the stone at currentRank, the stone that was at
        // currentRank+1 shifts down to currentRank. The frog needs to advance
        // D-1 more positions from there (since the departure stone is gone).
        // New rank (0-indexed): (currentRank - 1 + D - 1) % remaining
        currentRank = ((currentRank - 1 + D - 1) % remaining + remaining) % remaining + 1;
    }

    for (int x : order) {
        cout << x << "\n";
    }

    return 0;
}

Source Files

Exact copied source-of-truth files. Edit solution.tex for the write-up and solution.cpp for the implementation.

TeX write-up competitive_programming/ioi/2002/frog/solution.tex

Exact copied write-up source.

Raw file
\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,amssymb,amsthm}
\usepackage{listings}
\usepackage{xcolor}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\newtheorem{theorem}{Theorem}

\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 2002 -- Frog}
\author{Solution}
\date{}

\begin{document}
\maketitle

\section{Problem Statement Summary}
$N$ stones ($N \le 10^5$) are arranged in a circle, numbered
$1$ through $N$. A frog sits on stone 1. Each jump, the frog advances
exactly $D$ stones clockwise. After each jump, the stone the frog
\emph{lands on} is removed. The frog then adjusts to the nearest
remaining stone (with specific tie-breaking rules).

Simulate the process and output the order in which stones are removed.

\section{Solution: Fenwick Tree for Order Statistics}

\subsection{Key Idea}
Maintain the set of remaining stones in a Fenwick tree, where
$\text{bit}[i] = 1$ if stone $i$ is present and $0$ otherwise. This
supports:
\begin{itemize}
  \item Finding the $k$-th remaining stone in $O(\log N)$ (binary
        lifting on the BIT).
  \item Removing a stone in $O(\log N)$.
\end{itemize}

\subsection{Circular Jump}
If there are $R$ stones remaining and the frog is at rank $r$ (1-indexed
among remaining stones), after removing the current stone ($R$ becomes
$R - 1$), the stones after the removed one shift down in rank. The
frog's new target rank is:
\[
  r' = \bigl((r - 1) + (D - 1)\bigr) \bmod R' + 1
  \qquad\text{where } R' = R - 1.
\]
This accounts for the fact that the current stone is removed before
jumping.

\section{C++ Implementation}

\begin{lstlisting}
#include <bits/stdc++.h>
using namespace std;

struct BIT {
    int n;
    vector<int> tree;

    BIT(int n) : n(n), tree(n + 1, 0) {}

    void update(int i, int val) {
        for (; i <= n; i += i & (-i))
            tree[i] += val;
    }

    int query(int i) {
        int s = 0;
        for (; i > 0; i -= i & (-i))
            s += tree[i];
        return s;
    }

    // Find the k-th element (1-indexed) via binary lifting.
    int kth(int k) {
        int pos = 0;
        for (int bm = 1 << __lg(n); bm > 0; bm >>= 1) {
            int next = pos + bm;
            if (next <= n && tree[next] < k) {
                k -= tree[next];
                pos = next;
            }
        }
        return pos + 1;
    }
};

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, D;
    cin >> N >> D;

    BIT bit(N);
    for (int i = 1; i <= N; i++)
        bit.update(i, 1);

    int remaining = N;
    int curRank = 1; // rank of stone 1 among remaining stones

    for (int step = 0; step < N; step++) {
        int stone = bit.kth(curRank);
        cout << stone << "\n";

        bit.update(stone, -1);
        remaining--;

        if (remaining == 0) break;

        // After removing the stone at curRank, compute new rank.
        // Ranks >= curRank shift down by 1, so the "next" stone
        // is now at curRank (if it exists). We advance D-1 more.
        curRank = ((curRank - 1 + D - 1) % remaining) + 1;
    }

    return 0;
}
\end{lstlisting}

\section{Complexity Analysis}
\begin{itemize}
  \item \textbf{Time:} $O(N \log N)$. Each of the $N$ steps performs
        one $k$-th element query ($O(\log N)$) and one update
        ($O(\log N)$).
  \item \textbf{Space:} $O(N)$.
\end{itemize}

\end{document}