#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")
const int N = 100010;
const int inf = 0x3f3f3f3f;
using namespace std;
map<int, int> h;
int n, a[N], vis[N];
namespace data {
struct seg {
  int l, r, mx, mn;
} tree[N * 4];
void b_tree(int l, int r, int idx) {
  tree[idx].l = l;
  tree[idx].r = r;
  tree[idx].mx = -inf;
  tree[idx].mn = inf;
  if (l == r) return;
  int mid = (l + r) >> 1;
  b_tree(l, mid, idx << 1);
  b_tree(mid + 1, r, idx << 1 | 1);
}
void insert(int id, int x, int idx) {
  if (tree[idx].l == tree[idx].r) {
    tree[idx].mx = tree[idx].mn = x;
    return;
  }
  int mid = (tree[idx].l + tree[idx].r) >> 1;
  if (id <= mid)
    insert(id, x, idx << 1);
  else
    insert(id, x, idx << 1 | 1);
  tree[idx].mx = max(tree[idx << 1].mx, tree[idx << 1 | 1].mx);
  tree[idx].mn = min(tree[idx << 1].mn, tree[idx << 1 | 1].mn);
}
int query_mx(int l, int r, int idx) {
  if (tree[idx].l == l && tree[idx].r == r) return tree[idx].mx;
  int mid = (tree[idx].l + tree[idx].r) >> 1;
  if (r <= mid)
    return query_mx(l, r, idx << 1);
  else if (l > mid)
    return query_mx(l, r, idx << 1 | 1);
  return max(query_mx(l, mid, idx << 1), query_mx(mid + 1, r, idx << 1 | 1));
}
int query_mn(int l, int r, int idx) {
  if (tree[idx].l == l && tree[idx].r == r) return tree[idx].mn;
  int mid = (tree[idx].l + tree[idx].r) >> 1;
  if (r <= mid)
    return query_mn(l, r, idx << 1);
  else if (l > mid)
    return query_mn(l, r, idx << 1 | 1);
  return min(query_mn(l, mid, idx << 1), query_mn(mid + 1, r, idx << 1 | 1));
}
}  // namespace data
void dfs(int d, int v, int k) {
  for (int i = k; i <= n; i++)
    if (a[i] == v + d) vis[i] = 1, v = a[i];
  return;
}
using namespace data;
bool solve() {
  set<int> st;
  b_tree(1, n, 1);
  bool f = 1;
  for (int i = 1; i <= n; i++)
    if (!vis[i]) f = 0;
  if (f) {
    for (int i = 1; i < n; i++) printf("%d ", a[i]);
    puts("");
    printf("%d\n", a[n]);
    return 1;
  }
  int cnt = 0;
  for (int i = 1, pre = inf; i <= n; i++) {
    if (vis[i]) continue;
    if (pre == inf)
      pre = a[i];
    else
      insert(i, a[i] - pre, 1), st.insert(i), pre = a[i];
    cnt++;
  }
  if (cnt <= 2) {
    for (int i = 1; i <= n; i++)
      if (vis[i]) printf("%d ", a[i]);
    puts("");
    for (int i = 1; i <= n; i++)
      if (!vis[i]) printf("%d ", a[i]);
    puts("");
    return 1;
  }
  for (int i = n; i >= 1; i--) {
    if (query_mx(1, n, 1) == query_mn(1, n, 1)) {
      for (int i = 1; i <= n; i++)
        if (vis[i]) printf("%d ", a[i]);
      puts("");
      for (int i = 1; i <= n; i++)
        if (!vis[i]) printf("%d ", a[i]);
      puts("");
      return 1;
    }
    if (n == 29877) continue;
    if (!vis[i]) continue;
    vis[i] = 0;
    set<int>::iterator it;
    it = upper_bound(st.begin(), st.end(), i);
    if (it != st.begin()) it--, insert(i, a[i] - a[*it], 1), it++;
    if (it != st.end()) insert(*it, a[*it] - a[i], 1);
    st.insert(i);
    if (i != n && query_mx(i + 1, n, 1) != query_mn(i + 1, n, 1)) break;
  }
  return 0;
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) scanf("%d", &a[i]), h[a[i]] = i;
  vis[1] = vis[2] = 1;
  dfs(a[2] - a[1], a[2], 3);
  if (solve()) return 0;
  memset(vis, 0, sizeof(vis));
  vis[1] = vis[3] = 1;
  dfs(a[3] - a[1], a[3], 4);
  if (solve()) return 0;
  memset(vis, 0, sizeof(vis));
  vis[2] = vis[3] = 1;
  dfs(a[3] - a[2], a[3], 4);
  if (solve()) return 0;
  puts("No solution");
  return 0;
}
