All IOI entries
Competitive Programming

IOI 1998 - Contact

Problem Statement Given a binary string S of length n and integers a, b, k (1 a b 12, k 50), find the most frequently occurring bit patterns of length between a and b inclusive. Output the top k frequency groups (in d...

Source sync Apr 19, 2026
Track IOI
Year 1998
Files TeX and C++
Folder competitive_programming/ioi/1998/contact
IOI1998TeXC++

Source-first archive entry

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

Rendered from the "Problem Statement" section inside solution.tex because this entry has no separate statement file.

Given a binary string $S$ of length $n$ and integers $a$, $b$, $k$ ($1 \le a \le b \le 12$, $k \le 50$), find the most frequently occurring bit patterns of length between $a$ and $b$ inclusive.

Output the top $k$ frequency groups (in decreasing order of frequency). Within each group, patterns are sorted by length (shorter first), then by numeric value (smaller first). Each pattern is printed in binary.

Constraints: $|S| \le 200{,}000$.

Editorial

Rendered from the copied solution.tex file. The original TeX source remains available below.

Solution Approach

Counting All Substrings

Since pattern lengths are at most 12, each pattern fits in a 12-bit integer (values 0 to $2^{12} - 1 = 4095$). We maintain a 2D frequency table $\mathtt{cnt}[\ell][v]$ for length $\ell$ and value $v$.

For each starting position $i$, build the pattern incrementally:

val = 0
  for len = 1 to min(b, n - i):
      val = val * 2 + S[i + len - 1]
      if len >= a:
          cnt[len][val]++

Sorting and Output

Collect all (frequency, length, value) triples with positive frequency. Sort by frequency descending, then length ascending, then value ascending. Output the top $k$ frequency groups.

C++ Solution

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

char buf[200005];
int cnt[13][4096]; // cnt[len][val]

int main() {
    int a, b, k;
    scanf("%d %d %d", &a, &b, &k);

    // Read binary string (may span multiple lines)
    int n = 0;
    char line[100];
    while (scanf("%s", line) == 1) {
        for (int i = 0; line[i]; i++)
            buf[n++] = line[i] - '0';
    }

    memset(cnt, 0, sizeof(cnt));

    // Count all patterns of length a..b
    for (int i = 0; i < n; i++) {
        int val = 0;
        for (int len = 1; len <= b && i + len <= n; len++) {
            val = val * 2 + buf[i + len - 1];
            if (len >= a)
                cnt[len][val]++;
        }
    }

    // Collect patterns with positive frequency
    struct Pattern {
        int freq, len, val;
    };
    vector<Pattern> patterns;
    for (int len = a; len <= b; len++)
        for (int v = 0; v < (1 << len); v++)
            if (cnt[len][v] > 0)
                patterns.push_back({cnt[len][v], len, v});

    // Sort: frequency descending, then length ascending, then value ascending
    sort(patterns.begin(), patterns.end(), [](const Pattern& x, const Pattern& y) {
        if (x.freq != y.freq) return x.freq > y.freq;
        if (x.len != y.len) return x.len < y.len;
        return x.val < y.val;
    });

    // Output top k frequency groups
    int groups = 0, i = 0;
    while (i < (int)patterns.size() && groups < k) {
        int curFreq = patterns[i].freq;
        printf("%d\n", curFreq);

        int lineCount = 0;
        while (i < (int)patterns.size() && patterns[i].freq == curFreq) {
            if (lineCount > 0) printf(" ");
            // Print binary representation with correct number of digits
            int len = patterns[i].len;
            int val = patterns[i].val;
            char bits[13];
            for (int j = len - 1; j >= 0; j--) {
                bits[j] = '0' + (val & 1);
                val >>= 1;
            }
            bits[len] = '\0';
            printf("%s", bits);
            lineCount++;
            i++;
        }
        printf("\n");
        groups++;
    }

    return 0;
}

Complexity Analysis

  • Time complexity: $O(n \cdot b)$ for counting, where $b \le 12$. Effectively $O(n)$. Sorting the patterns takes $O(P \log P)$ where $P \le (b - a + 1) \cdot 2^b \le 12 \cdot 4096 = 49{,}152$, which is negligible.

  • Space complexity: $O(b \cdot 2^b + n)$: the frequency table plus the input string.

Code

Exact copied C++ implementation from solution.cpp.

C++ competitive_programming/ioi/1998/contact/solution.cpp

Exact copied implementation source.

Raw file
// IOI 1998 - Contact
// Count bit patterns of length a..b in binary string, output top k frequency groups
// Time: O(n * b), Space: O(b * 2^b + n)
#include <bits/stdc++.h>
using namespace std;

char buf[200005];
int cnt[13][4096]; // cnt[len][val]

int main() {
    int a, b, k;
    scanf("%d %d %d", &a, &b, &k);

    // Read binary string (may span multiple lines)
    int n = 0;
    char line[100];
    while (scanf("%s", line) == 1) {
        for (int i = 0; line[i]; i++)
            buf[n++] = line[i] - '0';
    }

    memset(cnt, 0, sizeof(cnt));

    // Count all patterns of length a..b
    for (int i = 0; i < n; i++) {
        int val = 0;
        for (int len = 1; len <= b && i + len <= n; len++) {
            val = val * 2 + buf[i + len - 1];
            if (len >= a)
                cnt[len][val]++;
        }
    }

    // Collect all patterns with count > 0
    struct Pattern {
        int freq, len, val;
    };
    vector<Pattern> patterns;
    for (int len = a; len <= b; len++)
        for (int v = 0; v < (1 << len); v++)
            if (cnt[len][v] > 0)
                patterns.push_back({cnt[len][v], len, v});

    // Sort: freq desc, then len asc, then val asc
    sort(patterns.begin(), patterns.end(), [](const Pattern& x, const Pattern& y) {
        if (x.freq != y.freq) return x.freq > y.freq;
        if (x.len != y.len) return x.len < y.len;
        return x.val < y.val;
    });

    // Output top k frequency groups
    int groups = 0;
    int i = 0;
    while (i < (int)patterns.size() && groups < k) {
        int curFreq = patterns[i].freq;
        printf("%d\n", curFreq);

        int lineCount = 0;
        while (i < (int)patterns.size() && patterns[i].freq == curFreq) {
            if (lineCount > 0) printf(" ");
            // Print binary representation with leading zeros
            int len = patterns[i].len;
            int val = patterns[i].val;
            char bits[13];
            for (int j = len - 1; j >= 0; j--) {
                bits[j] = '0' + (val & 1);
                val >>= 1;
            }
            bits[len] = '\0';
            printf("%s", bits);
            lineCount++;
            i++;
        }
        printf("\n");
        groups++;
    }

    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/1998/contact/solution.tex

Exact copied write-up source.

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

\lstset{
  language=C++,
  basicstyle=\ttfamily\small,
  keywordstyle=\color{blue}\bfseries,
  commentstyle=\color{green!60!black},
  stringstyle=\color{red!70!black},
  numbers=left,
  numberstyle=\tiny\color{gray},
  numbersep=8pt,
  frame=single,
  breaklines=true,
  tabsize=4,
  showstringspaces=false
}

\title{IOI 1998 -- Contact}
\author{Solution}
\date{}

\begin{document}
\maketitle

\section{Problem Statement}

Given a binary string $S$ of length $n$ and integers $a$, $b$, $k$
($1 \le a \le b \le 12$, $k \le 50$), find the most frequently occurring bit
patterns of length between $a$ and $b$ inclusive.

Output the top $k$ frequency groups (in decreasing order of frequency).
Within each group, patterns are sorted by length (shorter first), then by
numeric value (smaller first). Each pattern is printed in binary.

\medskip
\noindent\textbf{Constraints:} $|S| \le 200{,}000$.

\section{Solution Approach}

\subsection{Counting All Substrings}

Since pattern lengths are at most 12, each pattern fits in a 12-bit integer
(values 0 to $2^{12} - 1 = 4095$). We maintain a 2D frequency table
$\mathtt{cnt}[\ell][v]$ for length $\ell$ and value $v$.

For each starting position $i$, build the pattern incrementally:
\begin{verbatim}
  val = 0
  for len = 1 to min(b, n - i):
      val = val * 2 + S[i + len - 1]
      if len >= a:
          cnt[len][val]++
\end{verbatim}

\subsection{Sorting and Output}

Collect all (frequency, length, value) triples with positive frequency.
Sort by frequency descending, then length ascending, then value ascending.
Output the top $k$ frequency groups.

\section{C++ Solution}

\begin{lstlisting}
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

char buf[200005];
int cnt[13][4096]; // cnt[len][val]

int main() {
    int a, b, k;
    scanf("%d %d %d", &a, &b, &k);

    // Read binary string (may span multiple lines)
    int n = 0;
    char line[100];
    while (scanf("%s", line) == 1) {
        for (int i = 0; line[i]; i++)
            buf[n++] = line[i] - '0';
    }

    memset(cnt, 0, sizeof(cnt));

    // Count all patterns of length a..b
    for (int i = 0; i < n; i++) {
        int val = 0;
        for (int len = 1; len <= b && i + len <= n; len++) {
            val = val * 2 + buf[i + len - 1];
            if (len >= a)
                cnt[len][val]++;
        }
    }

    // Collect patterns with positive frequency
    struct Pattern {
        int freq, len, val;
    };
    vector<Pattern> patterns;
    for (int len = a; len <= b; len++)
        for (int v = 0; v < (1 << len); v++)
            if (cnt[len][v] > 0)
                patterns.push_back({cnt[len][v], len, v});

    // Sort: frequency descending, then length ascending, then value ascending
    sort(patterns.begin(), patterns.end(), [](const Pattern& x, const Pattern& y) {
        if (x.freq != y.freq) return x.freq > y.freq;
        if (x.len != y.len) return x.len < y.len;
        return x.val < y.val;
    });

    // Output top k frequency groups
    int groups = 0, i = 0;
    while (i < (int)patterns.size() && groups < k) {
        int curFreq = patterns[i].freq;
        printf("%d\n", curFreq);

        int lineCount = 0;
        while (i < (int)patterns.size() && patterns[i].freq == curFreq) {
            if (lineCount > 0) printf(" ");
            // Print binary representation with correct number of digits
            int len = patterns[i].len;
            int val = patterns[i].val;
            char bits[13];
            for (int j = len - 1; j >= 0; j--) {
                bits[j] = '0' + (val & 1);
                val >>= 1;
            }
            bits[len] = '\0';
            printf("%s", bits);
            lineCount++;
            i++;
        }
        printf("\n");
        groups++;
    }

    return 0;
}
\end{lstlisting}

\section{Complexity Analysis}

\begin{itemize}
  \item \textbf{Time complexity:} $O(n \cdot b)$ for counting, where $b \le 12$.
        Effectively $O(n)$. Sorting the patterns takes $O(P \log P)$ where
        $P \le (b - a + 1) \cdot 2^b \le 12 \cdot 4096 = 49{,}152$, which is negligible.
  \item \textbf{Space complexity:} $O(b \cdot 2^b + n)$: the frequency table plus the
        input string.
\end{itemize}

\end{document}