/* GCC */

#include <stdio.h>
#include <algorithm>
#include <vector>

using namespace std;

int n;
vector<int> all; // Усі числа із вхідного файлу
pair<int, int> p[2]; // p[i] — пара з першого та другого члена i-ї прогресії

// Переставляє howMany найменших елементів із проміжку чисел з індексами від from до to
// на перші місця цього проміжку (тобто на місці з індексом from стоятиме найменший елемент,
// на місці from+1 — другий за величиною і т. д.).
void swapSmallest(vector<int>::iterator from, vector<int>::iterator to, int howMany)
{
    for (int i = 0; i < howMany; i++)
        iter_swap(from + i, min_element(from + i, to));
}

// Визначає, чи належить число number n-елементній арифметичній прогресії з першим
// членом first та другим членом second.
inline bool belongsToProgression(int number, int first, int second, int n)
{
    int d = second - first, cur = number - first;
    return cur >= 0 && cur % d == 0 && cur / d < n;
}

// Функція test пробує розбити послідовність на дві прогресії за припущення, що в однієї
// з прогресій (яку умовно назвемо першою) перший елемент дорівнює first, а другий — second.
// Якщо розбити послідовність на прогресії вдалося, повертає true, інакше — false. У разі
// успіху заповнює глобальний масив p парами з перших і других членів прогресій.
bool test(int first, int second)
{
    vector<int> leftovers; // Числа, що залишаться після вибирання членів першої прогресії
    for (int i = 0; i < all.size(); i++)
        if (! belongsToProgression(all[i], first, second, n))
        { // Якщо число не належить до першої прогресії, додаємо його до потенційної другої:
            leftovers.push_back(all[i]);
            if (leftovers.size() > n) // Гіпотеза не справдилася: у другій прогресії
                return false;         // може бути лише n елементів
        }
    // Якщо ми дійшли до цього місця, то з першою прогресією все добре, а в масиві
    // leftovers рівно n елементів. Залишилося з’ясувати, чи утворюють вони прогресію.
    swapSmallest(leftovers.begin(), leftovers.end(), 2); // Знаходимо два найменших елементи
    for (int i = 2; i < n; i++)
        if (! belongsToProgression(leftovers[i], leftovers[0], leftovers[1], n))
            return false; // Якщо хоча б один з решти елементів не «узгоджується» з двома
                          // першими, то гіпотеза не справдилася
    // Якщо ми дійшли аж сюди, то гіпотеза справдилася. Заповнюємо інформацію про прогресії:
    p[0] = make_pair(first, second);
    p[1] = make_pair(leftovers[0], leftovers[1]);
    return true;
}

int main()
{
    freopen("stamps.in", "r", stdin);
    freopen("stamps.out", "w", stdout);

    // Зчитуємо дані:
    scanf("%d", &n);
    for (int i = 0; i < 2 * n; i++)
    {
        int t;
        scanf("%d", &t);
        all.push_back(t);
    }

    // Переставляємо три найменших числа на перші місця:
    swapSmallest(all.begin(), all.end(), 3);

    // Послідовно перевіряємо гіпотези про те, що найменшими елементами однієї з прогресій
    // є деякі два з найменших трьох чисел відсортованої послідовності (оператори || потрібні,
    // щоб після виявлення істинної гіпотези не продовжувати розгляд інших):
    test(all[0], all[1]) || test(all[0], all[2]) || test(all[1], all[2]);

    if (p[0].first > p[1].first) // Забезпечуємо правильний порядок виведення
        swap(p[0], p[1]);

    // Виводимо прогресії:
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < n; j++)
            printf(j < n - 1 ? "%d " : "%d\n", p[i].first + j * (p[i].second - p[i].first));

    return 0;
}
