ICPC 2021
ICPC 2021

H. Prehistoric Programs

Archaeologists have discovered exciting clay tablets in deep layers of Alutila Cave. Nobody was able to decipher the script on the tablets, ex- cept for two symbols that seem to describe nested structures not unlike opening and closing parentheses in LISP....

Updated May 21, 2026
Track ICPC
Year 2021
Statement Text + PDF
TeXC++Statement textStatement PDF

Problem Statement

Formatted from the contest statement text, with sample tests broken out into copyable blocks.

Time limit 6 seconds

Archaeologists have discovered exciting clay tablets in deep layers of Alutila Cave. Nobody was able to decipher the script on the tablets, ex- cept for two symbols that seem to describe nested structures not unlike opening and closing parentheses in LISP. Could it be that humans wrote programs thousands of years ago? Taken together, the tablets appear to describe a great piece of work – perhaps a program, or an epic, or even tax records! Unsurprisingly, af- ter such a long time, the tablets are in a state of disorder. Your job is to arrange them into a sequence so that the resulting work has a prop- erly nested parenthesis structure. Considering only opening and closing parentheses, a properly nested structure is either

  • (), or
  • (A), where A is a properly nested structure, or Clay tablet with undeciphered script
  • AB, where A and B are properly nested structures. Source: Wikimedia Commons

Input

The first line of input contains one integer n (1 ≤ n ≤ 106 ), the number of tablets. Each of the remaining n lines describes a tablet, and contains a non-empty string of opening and closing parentheses; symbols unrelated to the nesting structure are omitted. The strings are numbered from 1 to n in the order that they appear in the input. The input contains at most 107 parentheses.

Output

Output a permutation of the numbers from 1 to n such that concatenating the strings in this order re- sults in a properly nested structure. If this happens for multiple permutations, any one of them will be accepted. If there is no such permutation, output impossible instead.

Sample Tests

Sample 1
Sample Input
 2
 ())())()
 ((()
Sample Output
2
1
Sample 2
Sample Input
5
(
))
((
))
(
Sample Output
1
5
3
2
4
Sample 3
Sample Input
2
((
)
Sample Output
impossible

Editorial

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

Per-Tablet Statistics

For one string, define:

  • $\text{bal}$: total balance, where ( is $+1$ and ) is $-1$;

  • $\text{minPref}$: the minimum prefix balance inside that string.

  • If the current balance before appending this string is $B$, then the string is safe to append exactly when \[ B + \text{minPref} \ge 0. \] After appending it, the new balance becomes \[ B + \text{bal}. \]

Split into Two Groups

Strings with nonnegative total balance are helpful: once we append them, the available balance never gets smaller in the long run. Strings with negative total balance are dangerous and should be postponed.

So we split all tablets into:

  • positive group: $\text{bal} \ge 0$;

  • negative group: $\text{bal} < 0$.

  • If a valid order exists at all, there is one where all positive-group strings come first and all negative-group strings come last.

How to Sort the Positive Group

Inside the positive group, we want the least demanding strings first: the ones that require the smallest starting balance. That means sorting by \[ \text{minPref} \] in decreasing order.

Then we greedily append them in that order, checking \[ B + \text{minPref} \ge 0. \]

How to Sort the Negative Group

For negative-balance strings, the right measure is not just $\text{minPref}$, because after appending the string we lose some balance permanently.

The standard way to view this group is to reverse each string and swap open/close parentheses. This turns it into a positive-balance problem. Under that transformation, the relevant key becomes \[ \text{bal} - \text{minPref}. \]

Therefore the negative group should be sorted by \[ \text{bal} - \text{minPref} \] in decreasing order, and then greedily appended in that order.

Algorithm

  1. For each string, compute $\text{bal}$ and $\text{minPref}$.

  2. If the total balance over all strings is not zero, output impossible.

  3. Split strings into the positive and negative groups.

  4. Sort:

    • positive group by decreasing $\text{minPref}$;

    • negative group by decreasing $\text{bal} - \text{minPref}$.

    • Traverse first the sorted positive group, then the sorted negative group.

    • Maintain the current balance $B$. If some string has \[ B + \text{minPref} < 0, \] output impossible.

    • Otherwise append it, update \[ B \leftarrow B + \text{bal}, \] and record the index. enumerate

      Correctness Proof

      We prove that the algorithm outputs a valid permutation exactly when one exists.

      Lemma 1.

      If a string with statistics $(\text{bal}, \text{minPref})$ is appended when the current balance is $B$, then the concatenation remains prefix-valid if and only if \[ B + \text{minPref} \ge 0. \]

      Proof.

      Inside the string, every prefix changes the balance by exactly the corresponding prefix balance of that string. The worst such drop is $\text{minPref}$. So all resulting prefixes stay nonnegative exactly when the minimum possible one, namely $B+\text{minPref}$, is nonnegative. □

      Lemma 2.

      If a valid ordering exists, then there also exists a valid ordering in which every string with $\text{bal} \ge 0$ appears before every string with $\text{bal} < 0$.

      Proof.

      A nonnegative-balance string never reduces the total available balance after it is appended, while a negative-balance string does. Swapping a negative string that appears before a nonnegative string cannot make the future balance smaller at the point where the nonnegative string starts. Repeating this exchange process pushes all nonnegative strings to the front without destroying validity. □

      Lemma 3.

      Among strings with $\text{bal} \ge 0$, sorting by decreasing $\text{minPref}$ is optimal for greedy construction.

      Proof.

      Take two such strings $A$ and $B$ with $\text{minPref}(A) \ge \text{minPref}(B)$. If some current balance $X$ can append $B$ first, then \[ X + \text{minPref}(B) \ge 0. \] Since $\text{minPref}(A)$ is at least as large, $A$ is also appendable from $X$. After appending $A$, the balance does not decrease overall because $\text{bal}(A)\ge0$, so whatever was possible after $B$ remains possible after $A$. Thus placing the larger $\text{minPref}$ first is never worse. □

      Lemma 4.

      Among strings with $\text{bal} < 0$, sorting by decreasing $\text{bal} - \text{minPref}$ is optimal.

      Proof.

      Reverse each negative string and swap every parenthesis. This transforms it into a string with nonnegative total balance. Under this transformation, the role of $\text{minPref}$ becomes exactly \[ \text{bal} - \text{minPref}. \] So by Lemma 3, the transformed strings should be sorted by decreasing that quantity. Reversing the transformation gives exactly the claimed order for the original negative strings. □

      Theorem.

      The algorithm outputs a valid permutation if and only if one exists.

      Proof.

      By Lemma 2, it is enough to consider orders with all positive strings first and all negative strings last. By Lemma 3, the chosen order is optimal for the positive group, and by Lemma 4 it is optimal for the negative group. During the final scan, Lemma 1 exactly characterizes whether each next string can be appended safely.

      Therefore, if the algorithm fails, no valid ordering exists. If it succeeds, every prefix stays nonnegative and the total balance is zero, so the produced order is a correct bracket sequence. □

      Complexity Analysis

      Let $L$ be the total number of parentheses in the input. Computing all statistics takes $O(L)$ time. Sorting the tablets takes $O(n \log n)$ time. The memory usage is $O(n)$.

      Implementation Notes

      • We never need to store the full strings after computing $(\text{bal}, \text{minPref})$.

      • The final total balance must be zero; otherwise a correct bracket sequence is impossible no matter how we permute the tablets.

Code

C++ solution used for this page.

C++

Clean code view with a raw-file link when you want the original source.

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

namespace {

struct Tablet {
    int index;
    int balance;
    int min_prefix;
};

bool appendable(int current_balance, const Tablet& tablet) {
    return current_balance + tablet.min_prefix >= 0;
}

void solve() {
    int n;
    cin >> n;

    vector<Tablet> positive;
    vector<Tablet> negative;
    positive.reserve(n);
    negative.reserve(n);

    long long total_balance = 0;

    for (int i = 1; i <= n; ++i) {
        string s;
        cin >> s;

        int balance = 0;
        int min_prefix = 0;
        for (char ch : s) {
            balance += (ch == '(' ? 1 : -1);
            min_prefix = min(min_prefix, balance);
        }

        total_balance += balance;
        Tablet tablet = {i, balance, min_prefix};
        if (balance >= 0) {
            positive.push_back(tablet);
        } else {
            negative.push_back(tablet);
        }
    }

    if (total_balance != 0) {
        cout << "impossible\n";
        return;
    }

    sort(positive.begin(), positive.end(), [](const Tablet& lhs, const Tablet& rhs) {
        return lhs.min_prefix > rhs.min_prefix;
    });

    sort(negative.begin(), negative.end(), [](const Tablet& lhs, const Tablet& rhs) {
        return lhs.balance - lhs.min_prefix > rhs.balance - rhs.min_prefix;
    });

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

    int current_balance = 0;
    for (const Tablet& tablet : positive) {
        if (!appendable(current_balance, tablet)) {
            cout << "impossible\n";
            return;
        }
        current_balance += tablet.balance;
        order.push_back(tablet.index);
    }

    for (const Tablet& tablet : negative) {
        if (!appendable(current_balance, tablet)) {
            cout << "impossible\n";
            return;
        }
        current_balance += tablet.balance;
        order.push_back(tablet.index);
    }

    if (current_balance != 0) {
        cout << "impossible\n";
        return;
    }

    for (int index : order) {
        cout << index << '\n';
    }
}

}  // namespace

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

    solve();
    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