All IOI entries
Competitive Programming

IOI 2004 - Artemis

Problem Statement Summary Given N points in the plane, find an axis-aligned rectangle containing the maximum number of points strictly in its interior (no point on the boundary). Solution: Sweep with Maximum Subarray...

Source sync Apr 19, 2026
Track IOI
Year 2004
Files TeX and C++
Folder competitive_programming/ioi/2004/artemis
IOI2004TeXC++

Source-first archive entry

This page is built from the copied files in competitive_programming/ioi/2004/artemis. Edit competitive_programming/ioi/2004/artemis/solution.tex to update the written solution and competitive_programming/ioi/2004/artemis/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 $N$ points in the plane, find an axis-aligned rectangle containing the maximum number of points strictly in its interior (no point on the boundary).

Solution: Sweep with Maximum Subarray

Key Observations

  1. Since no point may lie on the boundary, the rectangle's sides must be placed in gaps between consecutive distinct coordinate values.

  2. Only the $O(N)$ distinct $x$- and $y$-coordinates matter for placing sides (coordinate compression).

  3. Fix the left and right boundaries (choosing from gaps between consecutive $x$-groups). The interior points form a one-dimensional problem: find the $y$-interval maximizing the count.

Algorithm

  1. Group points by their $x$-coordinate and sort the groups.

  2. Compress $y$-coordinates.

  3. For each left boundary $l$ (placed just right of $x$-group $l$), sweep the right boundary $r$ rightward:

    • When $r$ advances past group $g$, add group $g$'s points to a column histogram $\mathrm{cnt}[y]$.

    • After each update, find the maximum contiguous subarray sum of $\mathrm{cnt}[]$ (Kadane's algorithm in $O(M)$ where $M$ is the number of distinct $y$-values).

    • The maximum over all $(l, r)$ pairs is the answer. enumerate

      Correctness of Kadane's Step

      Choosing the best $y$-interval corresponds to finding bottom/top boundaries that maximize the number of interior points. Since boundaries are placed in gaps between distinct $y$-values, all points in a contiguous range of compressed $y$-indices are captured. This is exactly the maximum contiguous subarray sum.

      C++ Implementation

      #include <bits/stdc++.h>
      using namespace std;
      
      int main() {
          ios::sync_with_stdio(false);
          cin.tie(nullptr);
      
          int N;
          cin >> N;
      
          vector<int> px(N), py(N);
          for (int i = 0; i < N; i++)
              cin >> px[i] >> py[i];
      
          // Compress y-coordinates
          vector<int> ys = py;
          sort(ys.begin(), ys.end());
          ys.erase(unique(ys.begin(), ys.end()), ys.end());
          int M = ys.size();
      
          vector<int> cy(N);
          for (int i = 0; i < N; i++)
              cy[i] = lower_bound(ys.begin(), ys.end(), py[i]) - ys.begin();
      
          // Sort points by x, group by distinct x-values
          vector<int> order(N);
          iota(order.begin(), order.end(), 0);
          sort(order.begin(), order.end(),
               [&](int a, int b) { return px[a] < px[b]; });
      
          vector<vector<int>> groups; // groups[g] = list of compressed y-indices
          for (int i = 0; i < N; ) {
              int j = i;
              while (j < N && px[order[j]] == px[order[i]]) j++;
              vector<int> g;
              for (int k = i; k < j; k++)
                  g.push_back(cy[order[k]]);
              groups.push_back(g);
              i = j;
          }
      
          int G = groups.size();
          int ans = 0;
      
          // Enumerate left boundary (just right of group l)
          for (int l = 0; l < G; l++) {
              vector<int> cnt(M, 0);
              // Right boundary just left of group r; interior = groups l+1..r-1
              for (int r = l + 2; r < G; r++) {
                  // Add group r-1 (now strictly inside)
                  for (int y : groups[r - 1])
                      cnt[y]++;
      
                  // Kadane's algorithm: max contiguous subarray sum of cnt[]
                  int best = 0, cur = 0;
                  for (int y = 0; y < M; y++) {
                      cur += cnt[y];
                      best = max(best, cur);
                      if (cur < 0) cur = 0;
                  }
                  ans = max(ans, best);
              }
          }
      
          cout << ans << "\n";
          return 0;
      }

      Complexity Analysis

      • Time: $O(G^2 \cdot M)$ where $G \le N$ is the number of distinct $x$-groups and $M \le N$ is the number of distinct $y$-values. Worst case $O(N^3)$.

      • Space: $O(N)$.

      • For the IOI constraints ($N \le 20{,}000$), more sophisticated approaches using balanced BSTs or divide-and-conquer reduce the complexity to $O(N^2 \log N)$ or $O(N^2)$.

Code

Exact copied C++ implementation from solution.cpp.

C++ competitive_programming/ioi/2004/artemis/solution.cpp

Exact copied implementation source.

Raw file
// IOI 2004 - Artemis
// Find axis-aligned rectangle with max points strictly in interior.
// O(N^2 * M) via sweep on x-groups, Kadane on y for best interval.
#include <bits/stdc++.h>
using namespace std;

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

    int N;
    cin >> N;
    if (N <= 2) { cout << 0 << "\n"; return 0; }

    vector<int> px(N), py(N);
    for (int i = 0; i < N; i++) cin >> px[i] >> py[i];

    // Coordinate compression for y
    vector<int> ys = py;
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());
    int M = (int)ys.size();

    vector<int> cy(N);
    for (int i = 0; i < N; i++)
        cy[i] = (int)(lower_bound(ys.begin(), ys.end(), py[i]) - ys.begin());

    // Sort points by x, group by same x
    vector<int> order(N);
    iota(order.begin(), order.end(), 0);
    sort(order.begin(), order.end(), [&](int a, int b) {
        return px[a] < px[b];
    });

    vector<vector<int>> groups;
    for (int i = 0; i < N; ) {
        int j = i;
        while (j < N && px[order[j]] == px[order[i]]) j++;
        vector<int> g;
        for (int k = i; k < j; k++) g.push_back(cy[order[k]]);
        groups.push_back(g);
        i = j;
    }

    int G = (int)groups.size();
    int ans = 0;

    // Enumerate left boundary (just right of column l).
    // Sweep right boundary; columns strictly between l and r are interior.
    for (int l = 0; l < G; l++) {
        vector<int> cnt(M, 0);
        for (int r = l + 1; r < G; r++) {
            // Column r-1 is now strictly inside if r-1 > l
            if (r - 1 > l) {
                for (int y : groups[r - 1]) cnt[y]++;
            }
            // Best y-interval: max contiguous subarray sum (Kadane)
            int best = 0, cur = 0;
            for (int y = 0; y < M; y++) {
                cur += cnt[y];
                best = max(best, cur);
                if (cur < 0) cur = 0;
            }
            ans = max(ans, best);
        }
    }

    cout << ans << "\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/2004/artemis/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}
\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 2004 -- Artemis}
\author{Solution}
\date{}

\begin{document}
\maketitle

\section{Problem Statement Summary}
Given $N$ points in the plane, find an axis-aligned rectangle containing
the maximum number of points \emph{strictly} in its interior (no point
on the boundary).

\section{Solution: Sweep with Maximum Subarray}

\subsection{Key Observations}
\begin{enumerate}
  \item Since no point may lie on the boundary, the rectangle's sides
        must be placed in gaps between consecutive distinct coordinate
        values.
  \item Only the $O(N)$ distinct $x$- and $y$-coordinates matter for
        placing sides (coordinate compression).
  \item Fix the left and right boundaries (choosing from gaps between
        consecutive $x$-groups). The interior points form a
        one-dimensional problem: find the $y$-interval maximizing the
        count.
\end{enumerate}

\subsection{Algorithm}
\begin{enumerate}
  \item Group points by their $x$-coordinate and sort the groups.
  \item Compress $y$-coordinates.
  \item For each left boundary $l$ (placed just right of
        $x$-group $l$), sweep the right boundary $r$ rightward:
        \begin{itemize}
          \item When $r$ advances past group $g$, add group $g$'s
                points to a column histogram $\mathrm{cnt}[y]$.
          \item After each update, find the maximum contiguous subarray
                sum of $\mathrm{cnt}[]$ (Kadane's algorithm in $O(M)$
                where $M$ is the number of distinct $y$-values).
        \end{itemize}
  \item The maximum over all $(l, r)$ pairs is the answer.
\end{enumerate}

\subsection{Correctness of Kadane's Step}
Choosing the best $y$-interval corresponds to finding bottom/top
boundaries that maximize the number of interior points. Since boundaries
are placed in gaps between distinct $y$-values, all points in a
contiguous range of compressed $y$-indices are captured. This is
exactly the maximum contiguous subarray sum.

\section{C++ Implementation}

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

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

    int N;
    cin >> N;

    vector<int> px(N), py(N);
    for (int i = 0; i < N; i++)
        cin >> px[i] >> py[i];

    // Compress y-coordinates
    vector<int> ys = py;
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());
    int M = ys.size();

    vector<int> cy(N);
    for (int i = 0; i < N; i++)
        cy[i] = lower_bound(ys.begin(), ys.end(), py[i]) - ys.begin();

    // Sort points by x, group by distinct x-values
    vector<int> order(N);
    iota(order.begin(), order.end(), 0);
    sort(order.begin(), order.end(),
         [&](int a, int b) { return px[a] < px[b]; });

    vector<vector<int>> groups; // groups[g] = list of compressed y-indices
    for (int i = 0; i < N; ) {
        int j = i;
        while (j < N && px[order[j]] == px[order[i]]) j++;
        vector<int> g;
        for (int k = i; k < j; k++)
            g.push_back(cy[order[k]]);
        groups.push_back(g);
        i = j;
    }

    int G = groups.size();
    int ans = 0;

    // Enumerate left boundary (just right of group l)
    for (int l = 0; l < G; l++) {
        vector<int> cnt(M, 0);
        // Right boundary just left of group r; interior = groups l+1..r-1
        for (int r = l + 2; r < G; r++) {
            // Add group r-1 (now strictly inside)
            for (int y : groups[r - 1])
                cnt[y]++;

            // Kadane's algorithm: max contiguous subarray sum of cnt[]
            int best = 0, cur = 0;
            for (int y = 0; y < M; y++) {
                cur += cnt[y];
                best = max(best, cur);
                if (cur < 0) cur = 0;
            }
            ans = max(ans, best);
        }
    }

    cout << ans << "\n";
    return 0;
}
\end{lstlisting}

\section{Complexity Analysis}
\begin{itemize}
  \item \textbf{Time:} $O(G^2 \cdot M)$ where $G \le N$ is the number
        of distinct $x$-groups and $M \le N$ is the number of distinct
        $y$-values. Worst case $O(N^3)$.
  \item \textbf{Space:} $O(N)$.
\end{itemize}

For the IOI constraints ($N \le 20{,}000$), more sophisticated
approaches using balanced BSTs or divide-and-conquer reduce the
complexity to $O(N^2 \log N)$ or $O(N^2)$.

\end{document}