Problem:
Score : 1400 points

Problem Statement

You are given P, a permutation of (1,\ 2,\ ...\ N).

A string S of length N consisting of 0 and 1 is a good string when it meets the following criterion:

The sequences X and Y are constructed as follows:

First, let X and Y be empty sequences.

For each i=1,\ 2,\ ...\ N, in this order, append P_i to the end of X if S_i= 0, and append it to the end of Y if S_i= 1.

If X and Y have the same number of high elements, S is a good string.
Here, the i-th element of a sequence is called high when that element is the largest among the elements from the 1-st to i-th element in the sequence.

Determine if there exists a good string. If it exists, find the lexicographically smallest such string.

Constraints

1 \leq N \leq 2 \times 10^5

1 \leq P_i \leq N

P_1,\ P_2,\ ...\ P_N are all distinct.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
P_1 P_2 ... P_N

Output

If a good string does not exist, print -1.
If it exists, print the lexicographically smallest such string.

Sample Input 1

6
3 1 4 6 2 5

Sample Output 1

001001

Let S= 001001. Then, X=(3,\ 1,\ 6,\ 2) and Y=(4,\ 5).
The high elements in X is the first and third elements, and the high elements in Y is the first and second elements.
As they have the same number of high elements, 001001 is a good string.
There is no good string that is lexicographically smaller than this, so the answer is 001001.

Sample Input 2

5
1 2 3 4 5

Sample Output 2

-1

Sample Input 3

7
1 3 2 5 6 4 7

Sample Output 3

0001101

Sample Input 4

30
1 2 6 3 5 7 9 8 11 12 10 13 16 23 15 18 14 24 22 26 19 21 28 17 4 27 29 25 20 30

Sample Output 4

000000000001100101010010011101

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define FILL(a, n, x) memset((a), (x), sizeof ((a)[0]) * (n))
#define FILLA(a, x) memset((a), (x), sizeof (a))
#define COPY(a, n, b) memcpy((b), (a), sizeof ((a)[0]) * (n))
#define COPYA(a, b) memcpy((b), (a), sizeof (a))
using namespace std;

typedef pair<int, int> pii;
typedef long long li;
typedef unsigned long long lu;
const int inf = ~0U >> 2;
const li infl = ~0LLU >> 2;

template <class T> inline void Min(T &x, T y) { if (y < x) x = y; }
template <class T> inline void Max(T &x, T y) { if (y > x) x = y; }

// ----------------------------------------

const int maxn = 2e5;

struct Data {
  int maxv[2];

  void operator += (const Data &b) {
    Max(maxv[0], b.maxv[0]);
    Max(maxv[1], b.maxv[1]);
  }

  Data operator + (const Data &b) const {
    return {max(maxv[0], b.maxv[0]), max(maxv[1], b.maxv[1])};
  }
};

int n, P[maxn];
bool old[maxn];

namespace seg {
  const int max_node = 4e5 + 2e5 * 19;

  struct Node {
    int lc, rc;
    Data dat;
  } node[max_node];

  int nd;

  void Build(int u, int l, int r) {
    if (r - l == 1) {
      node[u] = {-1, -1, {0, -inf}};
    } else {
      node[u] = {nd, nd + 1, {0, -inf}};
      nd += 2;
      int mid = l + r >> 1;
      Build(node[u].lc, l, mid);
      Build(node[u].rc, mid, r);
    }
  }

  int Init(void) {
    nd = 1;
    Build(0, 0, n);
    return 0;
  }

  int ql, qr;
  Data qx;

  void QQuery(int u, int l, int r) {
    if (ql <= l && qr >= r) {
      qx += node[u].dat;
      return;
    }
    int mid = l + r >> 1;
    if (ql < mid) QQuery(node[u].lc, l, mid);
    if (qr > mid) QQuery(node[u].rc, mid, r);
  }

  Data Query(int root, int l, int r) {
    if (l >= r) return {0, -inf};
    qx = {0, -inf};
    ql = l;
    qr = r;
    QQuery(root, 0, n);
    return qx;
  }

  void Copy(int &u) {
    int v = nd++;
    node[v] = node[u];
    u = v;
  }

  void UUpdate(int &u, int l, int r) {
    Copy(u);
    if (r - l == 1) {
      node[u].dat += qx;
      return;
    }
    int mid = l + r >> 1;
    if (ql < mid) {
      UUpdate(node[u].lc, l, mid);
    } else {
      UUpdate(node[u].rc, mid, r);
    }
    node[u].dat = node[node[u].lc].dat + node[node[u].rc].dat;
  }

  int Update(int root, int i, const Data &x) {
    ql = i;
    qx = x;
    UUpdate(root, 0, n);
    return root;
  }
}

int root[maxn + 1];
int dire[maxn];
int tail[2];

int suf_old[maxn + 1];

bool Check(int i, int prev, int tail) {
  prev += suf_old[i];
  if (prev < 0) return false;
  int tar = prev;
  Data res = seg::Query(root[i], tail, n);
  // printf("Check(%d, %d, %d) = %d %d\n", i, prev, tail,
  //        res.maxv[0], res.maxv[1]);
  return res.maxv[tar & 1] >= tar;
}

int main(void) {
  scanf("%d", &n);
  for (int i = 0; i < n; ++i) {
    scanf("%d", P + i);
    --P[i];
  }
  int maxv = -1;
  FILL(old, n, 0);
  for (int i = 0; i < n; ++i) {
    if (P[i] > maxv) {
      maxv = P[i];
      old[i] = true;
    }
  }

  suf_old[n] = 0;
  for (int i = n - 1; i >= 0; --i) {
    suf_old[i] = suf_old[i + 1] + old[i];
  }

  root[n] = seg::Init();
  for (int i = n - 1; i >= 0; --i) {
    Data res = seg::Query(root[i + 1], P[i], n);
    Data now;
    if (old[i]) {
      now = (Data){res.maxv[0] + 2, res.maxv[1] + 2};
    } else {
      now = (Data){res.maxv[1] + 1, res.maxv[0] + 1};
    }
    root[i] = seg::Update(root[i + 1], P[i], now);
  }

  if (!Check(0, 0, 0)) {
    puts("-1");
    return 0;
  }

  tail[0] = tail[1] = -1;
  int lambda = 0;
  for (int i = 0; i < n; ++i) {
    // Try 0
    int tail_0 = tail[0];
    int lambda_0 = lambda;
    if (P[i] > tail[0]) {
      tail[0] = P[i];
      ++lambda;
    }
    if (Check(i + 1, lambda, tail[1]) || Check(i + 1, -lambda, tail[0])) {
      dire[i] = 0;
      continue;
    }
    lambda = lambda_0;
    tail[0] = tail_0;

    // Set 1
    if (P[i] > tail[1]) {
      tail[1] = P[i];
      --lambda;
    }
    dire[i] = 1;
  }

  for (int i = 0; i < n; ++i) {
    putchar('0' + dire[i]);
  }
  putchar('\n');
  return 0;
}