IOI 1990
IOI 1990

Subsets

We present two approaches: backtracking for small n and meet-in-the-middle for moderate n. Method 1: Backtracking (n 20) Enumerate subsets recursively, maintaining a running sum. At each position, either include or ex...

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

Problem Statement

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

Given a set of $n$ integers, find all subsets whose elements sum to a given target value $T$. Output each such subset.

Editorial

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

Solution

We present two approaches: backtracking for small $n$ and meet-in-the-middle for moderate $n$.

Method 1: Backtracking ($n \le 20$)

Enumerate subsets recursively, maintaining a running sum. At each position, either include or exclude the current element. When the sum equals $T$, output the current subset.

To avoid duplicate subsets when elements repeat, sort the array and skip consecutive equal elements at the same recursion level.

Method 2: Meet in the Middle ($n \le 40$)

Split the array into halves $A$ (first $\lfloor n/2 \rfloor$ elements) and $B$ (remaining elements). Enumerate all $2^{|A|}$ subset sums from $A$ and all $2^{|B|}$ subset sums from $B$. For each sum $s$ from $B$, look up $T - s$ among the sums from $A$.

Complexity Analysis

  • Backtracking: $O(2^n)$ worst case, significantly reduced by pruning in practice.

  • Meet in the Middle: $O(2^{n/2} \cdot n)$ time, $O(2^{n/2})$ space.

Implementation: Backtracking

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int n, target;
vector<int> arr;
vector<int> current;
int count_solutions = 0;

void backtrack(int idx, int sum) {
    if (sum == target && !current.empty()) {
        cout << "{ ";
        for (int x : current) cout << x << " ";
        cout << "}" << endl;
        count_solutions++;
    }
    if (idx == n) return;
    if (sum > target && arr[idx] > 0) return; // pruning for positive values

    for (int i = idx; i < n; i++) {
        // Skip duplicates at the same level
        if (i > idx && arr[i] == arr[i-1]) continue;
        current.push_back(arr[i]);
        backtrack(i + 1, sum + arr[i]);
        current.pop_back();
    }
}

int main() {
    cin >> n >> target;
    arr.resize(n);
    for (int i = 0; i < n; i++)
        cin >> arr[i];

    sort(arr.begin(), arr.end());
    backtrack(0, 0);

    if (count_solutions == 0)
        cout << "No subsets found." << endl;
    return 0;
}

Implementation: Meet in the Middle

#include <iostream>
#include <vector>
#include <map>
using namespace std;

int main() {
    int n, target;
    cin >> n >> target;
    vector<int> arr(n);
    for (int i = 0; i < n; i++)
        cin >> arr[i];

    int half = n / 2;
    int other = n - half;

    // Generate all subset sums for the first half
    map<int, vector<vector<int>>> leftSums;
    for (int mask = 0; mask < (1 << half); mask++) {
        int s = 0;
        vector<int> subset;
        for (int i = 0; i < half; i++) {
            if (mask & (1 << i)) {
                s += arr[i];
                subset.push_back(arr[i]);
            }
        }
        leftSums[s].push_back(subset);
    }

    // Generate all subset sums for the second half;
    // look up complement in leftSums
    for (int mask = 0; mask < (1 << other); mask++) {
        int s = 0;
        vector<int> subset;
        for (int i = 0; i < other; i++) {
            if (mask & (1 << i)) {
                s += arr[half + i];
                subset.push_back(arr[half + i]);
            }
        }
        int need = target - s;
        auto it = leftSums.find(need);
        if (it != leftSums.end()) {
            for (auto& left : it->second) {
                if (left.empty() && subset.empty()) continue;
                cout << "{ ";
                for (int x : left) cout << x << " ";
                for (int x : subset) cout << x << " ";
                cout << "}" << endl;
            }
        }
    }

    return 0;
}

Notes

  • The backtracking solution is the most natural for the original IOI 1990 constraints (small $n$). Sorting enables both pruning and duplicate avoidance.

  • The meet-in-the-middle approach extends the practical range to about $n = 40$. Its memory usage of $O(2^{n/2})$ is the main limiting factor.

  • Both solutions output all valid subsets. If only the count is needed, the meet-in-the-middle approach can use a simple frequency map instead of storing explicit subsets.

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 1990 - Problem 1: Subsets
// Find all subsets of n integers that sum to target T.
// Uses meet-in-the-middle for efficiency (handles n up to ~40).
#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, target;
    scanf("%d%d", &n, &target);
    vector<int> arr(n);
    for (int i = 0; i < n; i++)
        scanf("%d", &arr[i]);

    int half = n / 2;
    int other = n - half;

    // Generate all subset sums for the first half
    map<int, vector<vector<int>>> leftSums;
    for (int mask = 0; mask < (1 << half); mask++) {
        int s = 0;
        vector<int> subset;
        for (int i = 0; i < half; i++) {
            if (mask & (1 << i)) {
                s += arr[i];
                subset.push_back(arr[i]);
            }
        }
        leftSums[s].push_back(subset);
    }

    // Generate all subset sums for the second half, look up complement
    for (int mask = 0; mask < (1 << other); mask++) {
        int s = 0;
        vector<int> subset;
        for (int i = 0; i < other; i++) {
            if (mask & (1 << i)) {
                s += arr[half + i];
                subset.push_back(arr[half + i]);
            }
        }
        int need = target - s;
        auto it = leftSums.find(need);
        if (it != leftSums.end()) {
            for (auto& left : it->second) {
                if (left.empty() && subset.empty()) continue; // skip empty subset
                printf("{ ");
                for (int x : left) printf("%d ", x);
                for (int x : subset) printf("%d ", x);
                printf("}\n");
            }
        }
    }
    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