#include <bits/stdc++.h>
//
// Created by cuom1999 on 2/4/20.
//

#ifndef INC_20S_3353_PA01_ALLOCATOR_H
#define INC_20S_3353_PA01_ALLOCATOR_H
#include <iostream>
using namespace std;

class Allocator {
protected:
    static const size_t MEMORY = 128 * 1024 * 1024; // 256MB
    void* startMem = malloc(MEMORY);

public:
    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p) = 0;
    virtual void debug() = 0;
};

#endif //INC_20S_3353_PA01_ALLOCATOR_H

//
// Created by cuom1999 on 2/5/20.
//

#ifndef INC_20S_3353_PA01_MYVECTOR_H
#define INC_20S_3353_PA01_MYVECTOR_H
#include <cassert>

template <typename T>
class MyVector {

public:
    // constructors and destructors
    MyVector();
    MyVector(const int size);
    MyVector(const MyVector<T>&);
    ~MyVector();

    // assignment operator
    MyVector<T>& operator= (const MyVector<T>&);

    // getting data functions
    int getSize();
    int getCapacity();
    T& operator[] (const int);
    T& back(); // return the last element

    // modifying functions
    void pushBack(const T&);
    void popBack();
    void insert(int pos, const T&);
    void erase(int pos);

private:
    T *data;
    int size;
    int capacity;

    // this will double the capacity and reallocate data every time size exceeds capacity
    void reserve();
};

// -----------------------------------------
// implementation

template <typename T>
MyVector<T>::MyVector() {
    capacity = 10;
    size = 0;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const int size) {
    capacity = size;
    this->size = size;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const MyVector<T>& v) {
    size = v.size;
    capacity = v.capacity;
    data = (T*) malloc(capacity * sizeof(T));

    // copy all elements
    for (int i = 0; i < size; i++) {
        data[i] = v.data[i];
    }
}

template <typename T>
MyVector<T>::~MyVector() {
    free(data);
}

template <typename T>
MyVector<T>& MyVector<T>::operator= (const MyVector<T>& vec) {
    free(data);
    size = vec.size;
    capacity = vec.capacity;
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = vec.data[i];
    }
    return *this;
}

template <typename T>
int MyVector<T>::getSize() {
    return size;
}

template <typename T>
int MyVector<T>::getCapacity() {
    return capacity;
}

template <typename T>
T& MyVector<T>::operator[](const int pos) {
    return data[pos];
}

template <typename T>
T& MyVector<T>::back() {
    assert(size > 0);
    return data[size - 1];
}

template <typename T>
void MyVector<T>::reserve() {
    T* temp = (T*) malloc(size * sizeof(T));

    // copy all elements from data to temp;
    for (int i = 0; i < size; i++) {
        temp[i] = data[i];
    }

    // double capacity and reallocate the data to a new memory
    capacity *= 2;
    free(data);
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = temp[i];
    }
    free(temp);
}

template <typename T>
void MyVector<T>::pushBack(const T& obj) {
    if (size < capacity) { // we still have enough space
        data[size] = obj;
    }
    else { // need to reserve more space
        reserve();
        data[size] = obj;
    }
    size++;
}

template <typename T>
void MyVector<T>::popBack() {
    if (size) size--;
}

template <typename T>
void MyVector<T>::insert(int pos, const T& obj) {
    assert(0 <= pos && pos <= size);
    if (size >= capacity) reserve();

    for (int i = size; i > pos; i--) {
        data[i] = data[i - 1];
    }
    size++;
    data[pos] = obj;
}

template <typename T>
void MyVector<T>::erase(int pos) {
    assert(0 <= pos && pos < size);
    for (int i = pos; i < size; i++) {
        data[i] = data[i + 1];
    }
    size--;
}

#endif //INC_20S_3353_PA01_MYVECTOR_H

class BestFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;

public:
    BestFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

class FirstFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;
public:
    FirstFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {
        cout << "[";
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.getSize()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

class RandomFit: public Allocator {
public:
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

size_t intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}

BestFit::BestFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* BestFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void BestFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

FirstFit::FirstFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void FirstFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

void* RandomFit::getMem(size_t size) {
    return startMem;
}

void RandomFit::freeMem(void* p) {
    free(p);
}

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    static FirstFit firstFit;
    static BestFit bestFit;
    static RandomFit randomFit;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;
FirstFit AllocatorSingleton::firstFit = FirstFit();
BestFit AllocatorSingleton::bestFit = BestFit();
RandomFit AllocatorSingleton::randomFit = RandomFit();

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = &firstFit;
                break;
            case BEST_FIT:
                alloc = &bestFit;
                break;
            case RANDOM_FIT:
                alloc = &randomFit;
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

#define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


#include <bits/stdc++.h>
//
// Created by cuom1999 on 2/4/20.
//

#ifndef INC_20S_3353_PA01_ALLOCATOR_H
#define INC_20S_3353_PA01_ALLOCATOR_H
#include <iostream>
using namespace std;

class Allocator {
protected:
    static const size_t MEMORY = 256 * 1024 * 1024; // 256MB
    void* startMem = malloc(MEMORY);

public:
    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p) = 0;
    virtual void debug() = 0;
};

#endif //INC_20S_3353_PA01_ALLOCATOR_H

//
// Created by cuom1999 on 2/5/20.
//

#ifndef INC_20S_3353_PA01_MYVECTOR_H
#define INC_20S_3353_PA01_MYVECTOR_H
#include <cassert>

template <typename T>
class MyVector {

public:
    // constructors and destructors
    MyVector();
    MyVector(const int size);
    MyVector(const MyVector<T>&);
    ~MyVector();

    // assignment operator
    MyVector<T>& operator= (const MyVector<T>&);

    // getting data functions
    int getSize();
    int getCapacity();
    T& operator[] (const int);
    T& back(); // return the last element

    // modifying functions
    void pushBack(const T&);
    void popBack();
    void insert(int pos, const T&);
    void erase(int pos);

private:
    T *data;
    int size;
    int capacity;

    // this will double the capacity and reallocate data every time size exceeds capacity
    void reserve();
};

// -----------------------------------------
// implementation

template <typename T>
MyVector<T>::MyVector() {
    capacity = 10;
    size = 0;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const int size) {
    capacity = size;
    this->size = size;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const MyVector<T>& v) {
    size = v.size;
    capacity = v.capacity;
    data = (T*) malloc(capacity * sizeof(T));

    // copy all elements
    for (int i = 0; i < size; i++) {
        data[i] = v.data[i];
    }
}

template <typename T>
MyVector<T>::~MyVector() {
    free(data);
}

template <typename T>
MyVector<T>& MyVector<T>::operator= (const MyVector<T>& vec) {
    free(data);
    size = vec.size;
    capacity = vec.capacity;
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = vec.data[i];
    }
    return *this;
}

template <typename T>
int MyVector<T>::getSize() {
    return size;
}

template <typename T>
int MyVector<T>::getCapacity() {
    return capacity;
}

template <typename T>
T& MyVector<T>::operator[](const int pos) {
    return data[pos];
}

template <typename T>
T& MyVector<T>::back() {
    assert(size > 0);
    return data[size - 1];
}

template <typename T>
void MyVector<T>::reserve() {
    T* temp = (T*) malloc(size * sizeof(T));

    // copy all elements from data to temp;
    for (int i = 0; i < size; i++) {
        temp[i] = data[i];
    }

    // double capacity and reallocate the data to a new memory
    capacity *= 2;
    free(data);
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = temp[i];
    }
    free(temp);
}

template <typename T>
void MyVector<T>::pushBack(const T& obj) {
    if (size < capacity) { // we still have enough space
        data[size] = obj;
    }
    else { // need to reserve more space
        reserve();
        data[size] = obj;
    }
    size++;
}

template <typename T>
void MyVector<T>::popBack() {
    if (size) size--;
}

template <typename T>
void MyVector<T>::insert(int pos, const T& obj) {
    assert(0 <= pos && pos <= size);
    if (size >= capacity) reserve();

    for (int i = size; i > pos; i--) {
        data[i] = data[i - 1];
    }
    size++;
    data[pos] = obj;
}

template <typename T>
void MyVector<T>::erase(int pos) {
    assert(0 <= pos && pos < size);
    for (int i = pos; i < size; i++) {
        data[i] = data[i + 1];
    }
    size--;
}

#endif //INC_20S_3353_PA01_MYVECTOR_H

class BestFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;

public:
    BestFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

class FirstFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;
public:
    FirstFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {
        cout << "[";
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.getSize()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

class RandomFit: public Allocator {
public:
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

size_t intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}

BestFit::BestFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* BestFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void BestFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

FirstFit::FirstFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void FirstFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

void* RandomFit::getMem(size_t size) {
    return startMem;
}

void RandomFit::freeMem(void* p) {
    free(p);
}

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    static FirstFit firstFit;
    static BestFit bestFit;
    static RandomFit randomFit;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;
FirstFit AllocatorSingleton::firstFit = FirstFit();
BestFit AllocatorSingleton::bestFit = BestFit();
RandomFit AllocatorSingleton::randomFit = RandomFit();

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = &firstFit;
                break;
            case BEST_FIT:
                alloc = &bestFit;
                break;
            case RANDOM_FIT:
                alloc = &randomFit;
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

#define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


#include <bits/stdc++.h>

template <class T>
class STLAllocator {
public:
    typedef T value_type;

    T* allocate(std::size_t n) {
        return static_cast<T*>(std::malloc(n*sizeof(T)));
    }

    void deallocate(T* p, std::size_t)noexcept {
        std::free(p);
    }

};

//
// Created by cuom1999 on 2/4/20.
//

using namespace std;

class Allocator {
protected:
    static const size_t MEMORY = 50<<20; // 256MB
    void* startMem = malloc(MEMORY);

    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    vector<pair<size_t, size_t>, STLAllocator<pair<size_t, size_t>>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    vector<size_t, STLAllocator<size_t>> followMemSize;

    size_t intervalLen(const pair<size_t, size_t> &p);

public:
    Allocator();

    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p);

    void debug() {
        cout << "[";
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.size()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

//
// Created by cuom1999 on 2/11/20.
//

Allocator::Allocator() {
    emptyIntervals.push_back({0, MEMORY - 4});
    followMemSize.resize(MEMORY / 4);
}

void Allocator::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty size_terval list0
    pair<size_t, size_t> newsize_terval = {pos, pos + size - 4};

    size_t addedPosition = -1;

    // find the position to add
    if (newsize_terval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(emptyIntervals.begin(), newsize_terval);
        addedPosition = 0;
    }
    else {
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            if (emptyIntervals[i].second < newsize_terval.first) {
                // add after this size_terval

                if (newsize_terval.first == emptyIntervals[i].second + 4) {
                    // merge newsize_terval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newsize_terval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(emptyIntervals.begin() + i + 1, newsize_terval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.size()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(emptyIntervals.begin() + addedPosition + 1);
    }

    followMemSize[pos / 4] = 0;
}

size_t Allocator::intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}//
// Created by cuom1999 on 2/5/20.
//

using namespace std;

class FirstFit: public Allocator {
public:
    FirstFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

FirstFit::FirstFit() {

}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (size_t i = 0; i < emptyIntervals.size(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(emptyIntervals.begin() + i);
            }

            // mark followMemSize
            followMemSize[(size_t) validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}
//
// Created by cuom1999 on 2/5/20.
//

using namespace std;

class BestFit: public Allocator {
public:
    BestFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

BestFit::BestFit() {
}

void* BestFit::getMem(size_t size) {
    int bestPos = -1;
    size_t bestSize = 0;

    // find the bestPos - best fit block
    for (size_t i = 0; i < emptyIntervals.size(); i++) {
        size_t currLen = intervalLen(emptyIntervals[i]);
        if (currLen >= size) {
            // check if this is smaller than the current best block
            if (bestPos == -1 || bestSize > currLen) {
                bestSize = currLen;
                bestPos = i;
            }
        }
    }

    if (bestPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    size_t memPosition = emptyIntervals[bestPos].first;

    // modify the emptyIntervals
    emptyIntervals[bestPos].first += size;
    if (emptyIntervals[bestPos].first > emptyIntervals[bestPos].second) {
        emptyIntervals.erase(emptyIntervals.begin() + bestPos);
    }

    followMemSize[memPosition / 4] = size;

    return (uint8_t*) startMem + (size_t) memPosition;
}
//
// Created by cuom1999 on 2/5/20.
//

class RandomFit: public Allocator {
public:
    RandomFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

RandomFit::RandomFit() {

}

// In this Fit, we do the similar traversal as FirstFit but
// start at a random position
// First, choose a random interval, then travel to left and right at the
// same time to find the best interval that >= size
void* RandomFit::getMem(size_t size) {
    srand(time(0));

    size_t startPos = rand() % emptyIntervals.size(); // random startPos
    size_t leftPtr = startPos;
    size_t rightPtr = startPos;
    int validPos = -1;

    // check if startPos is big enough
    if (intervalLen(emptyIntervals[startPos]) >= size) {
        validPos = startPos;
    }

    // loop to find the first interval
    while (validPos == -1) {
        bool canContinue = false;

        if (rightPtr < emptyIntervals.size()) {
            canContinue = true;
            rightPtr++;
            if (intervalLen(emptyIntervals[rightPtr]) >= size) {
                validPos = rightPtr;
                break;
            }
        }

        if (leftPtr > 0) {
            canContinue = true;
            leftPtr--;
            if (intervalLen(emptyIntervals[leftPtr]) >= size) {
                validPos = leftPtr;
                break;
            }
        }
        if (!canContinue) break;
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    size_t memPosition = emptyIntervals[validPos].first;

    // modify the emptyIntervals
    emptyIntervals[validPos].first += size;
    if (emptyIntervals[validPos].first > emptyIntervals[validPos].second) {
        emptyIntervals.erase(emptyIntervals.begin() + validPos);
    }

    followMemSize[memPosition / 4] = size;

    return (uint8_t*) startMem + (size_t) memPosition;
}
//
// Created by cuom1999 on 2/4/20.
//

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = (FirstFit*) malloc(sizeof(FirstFit));
                new (alloc) FirstFit();
                break;
            case BEST_FIT:
                alloc = (BestFit*) malloc(sizeof(BestFit));
                new (alloc) BestFit();
                break;
            case RANDOM_FIT:
                alloc = (RandomFit*) malloc(sizeof(RandomFit));
                new (alloc) RandomFit();
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

//
// Created by cuom1999 on 2/5/20.
//

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

using namespace std;

 #define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    AllocatorSingleton::useBestFit();
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


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

class Allocator {
protected:
    static const size_t MEMORY = 100 << 20; // 256MB
    void* startMem = malloc(MEMORY);

public:
    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p) = 0;
    virtual void debug() = 0;
};

inline size_t intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}

//
// Created by cuom1999 on 2/6/20.
//

template <class T>
class STLAllocator {
public:
    typedef T value_type;

    T* allocate(std::size_t n) {
        return static_cast<T*>(std::malloc(n*sizeof(T)));
    }

    void deallocate(T* p, std::size_t)noexcept {
        std::free(p);
    }

};

//
// Created by cuom1999 on 2/5/20.
//

using namespace std;

class FirstFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    vector<pair<size_t, size_t>, STLAllocator<pair<size_t, size_t>>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    vector<size_t, STLAllocator<size_t>> followMemSize;
public:
    FirstFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {
        cout << "[";
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.size()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

//
// Created by cuom1999 on 2/5/20.
//

FirstFit::FirstFit() {
    // the entire memory we have (256MB)
    emptyIntervals.push_back({0, MEMORY - 4});
    followMemSize.resize(MEMORY / 4);
}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (size_t i = 0; i < emptyIntervals.size(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(emptyIntervals.begin() + i);
            }

            // mark followMemSize
            followMemSize[(size_t) validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void FirstFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty size_terval list0
    pair<size_t, size_t> newsize_terval = {pos, pos + size - 4};

    size_t addedPosition = -1;

    // find the position to add
    if (newsize_terval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(emptyIntervals.begin(), newsize_terval);
        addedPosition = 0;
    }
    else {
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            if (emptyIntervals[i].second < newsize_terval.first) {
                // add after this size_terval

                if (newsize_terval.first == emptyIntervals[i].second + 4) {
                    // merge newsize_terval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newsize_terval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(emptyIntervals.begin() + i + 1, newsize_terval);
                }
                break;
            }
        }
    }

    // merge newsize_terval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.size()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(emptyIntervals.begin() + addedPosition + 1);
    }

    followMemSize[pos / 4] = 0;
}

//
// Created by cuom1999 on 2/5/20.
//

class BestFit: public Allocator {
private:

public:
//    BestFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

//
// Created by cuom1999 on 2/5/20.
//

void* BestFit::getMem(size_t size) {
    return startMem;
}

void BestFit::freeMem(void* p) {
    free(p);
}//
// Created by cuom1999 on 2/5/20.
//

class RandomFit: public Allocator {
public:
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

//
// Created by cuom1999 on 2/5/20.
//

void* RandomFit::getMem(size_t size) {
    return startMem;
}

void RandomFit::freeMem(void* p) {
    free(p);
}//
// Created by cuom1999 on 2/4/20.
//

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = (FirstFit*) malloc(sizeof(FirstFit));
                new (alloc) FirstFit();
                break;
            case BEST_FIT:
                alloc = (BestFit*) malloc(sizeof(BestFit));
                new (alloc) BestFit();
                break;
            case RANDOM_FIT:
                alloc = (RandomFit*) malloc(sizeof(RandomFit));
                new (alloc) RandomFit();
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

//
// Created by cuom1999 on 2/5/20.
//

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

 #define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


#include <bits/stdc++.h>

#define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;

    vector<int> a(n + 1);
    vector<int> gave(n + 1), given(n + 1);

    FOR (i, 1, n) {
        cin >> a[i];
        if (a[i]) {
            gave[i] = 1;
            given[a[i]] = 1;
        }
    }

    vector<int> fixedPoints;
    FOR (i, 1, n) {
        if (!gave[i] && !given[i]) {
            fixedPoints.pb(i);
        }
    }

    if (fixedPoints.size() > 1) {
        for (int i = 0; i < fixedPoints.size(); i++) {
            a[fixedPoints[i]] = fixedPoints[(i + 1) % fixedPoints.size()];
        }
        for (auto i: fixedPoints) {
            given[i] = gave[i] = 1;
        }
    }
    int special = -1;

    if (fixedPoints.size() == 1) {
        special = fixedPoints[0];
        given[special] = gave[special] = 1;
    }

    vector<int> give, receive;
    FOR (i, 1, n) {
        if (!gave[i]) give.pb(i);
        if (!given[i]) receive.pb(i);
    }

    if (special != -1) {
        a[special] = receive[0];
        receive[0] = special;
    }

    for (int i = 0; i < give.size(); i++) {
        a[give[i]] = receive[i];
    }

    FOR (i, 1, n) cout << a[i] << " ";

    return 0;
}


#include <bits/stdc++.h>
//
// Created by cuom1999 on 2/4/20.
//

#ifndef INC_20S_3353_PA01_ALLOCATOR_H
#define INC_20S_3353_PA01_ALLOCATOR_H
#include <iostream>
using namespace std;

class Allocator {
protected:
    static const size_t MEMORY = 40 * 1024 * 1024; // 256MB
    void* startMem = malloc(MEMORY);

public:
    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p) = 0;
    virtual void debug() = 0;
};

#endif //INC_20S_3353_PA01_ALLOCATOR_H

//
// Created by cuom1999 on 2/5/20.
//

#ifndef INC_20S_3353_PA01_MYVECTOR_H
#define INC_20S_3353_PA01_MYVECTOR_H
#include <cassert>

template <typename T>
class MyVector {

public:
    // constructors and destructors
    MyVector();
    MyVector(const int size);
    MyVector(const MyVector<T>&);
    ~MyVector();

    // assignment operator
    MyVector<T>& operator= (const MyVector<T>&);

    // getting data functions
    int getSize();
    int getCapacity();
    T& operator[] (const int);
    T& back(); // return the last element

    // modifying functions
    void pushBack(const T&);
    void popBack();
    void insert(int pos, const T&);
    void erase(int pos);

private:
    T *data;
    int size;
    int capacity;

    // this will double the capacity and reallocate data every time size exceeds capacity
    void reserve();
};

// -----------------------------------------
// implementation

template <typename T>
MyVector<T>::MyVector() {
    capacity = 10;
    size = 0;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const int size) {
    capacity = size;
    this->size = size;
    data = (T*) malloc(capacity * sizeof(T));
}

template <typename T>
MyVector<T>::MyVector(const MyVector<T>& v) {
    size = v.size;
    capacity = v.capacity;
    data = (T*) malloc(capacity * sizeof(T));

    // copy all elements
    for (int i = 0; i < size; i++) {
        data[i] = v.data[i];
    }
}

template <typename T>
MyVector<T>::~MyVector() {
    free(data);
}

template <typename T>
MyVector<T>& MyVector<T>::operator= (const MyVector<T>& vec) {
    free(data);
    size = vec.size;
    capacity = vec.capacity;
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = vec.data[i];
    }
    return *this;
}

template <typename T>
int MyVector<T>::getSize() {
    return size;
}

template <typename T>
int MyVector<T>::getCapacity() {
    return capacity;
}

template <typename T>
T& MyVector<T>::operator[](const int pos) {
    return data[pos];
}

template <typename T>
T& MyVector<T>::back() {
    assert(size > 0);
    return data[size - 1];
}

template <typename T>
void MyVector<T>::reserve() {
    T* temp = (T*) malloc(size * sizeof(T));

    // copy all elements from data to temp;
    for (int i = 0; i < size; i++) {
        temp[i] = data[i];
    }

    // double capacity and reallocate the data to a new memory
    capacity *= 2;
    free(data);
    data = (T*) malloc(capacity * sizeof(T));
    for (int i = 0; i < size; i++) {
        data[i] = temp[i];
    }
    free(temp);
}

template <typename T>
void MyVector<T>::pushBack(const T& obj) {
    if (size < capacity) { // we still have enough space
        data[size] = obj;
    }
    else { // need to reserve more space
        reserve();
        data[size] = obj;
    }
    size++;
}

template <typename T>
void MyVector<T>::popBack() {
    if (size) size--;
}

template <typename T>
void MyVector<T>::insert(int pos, const T& obj) {
    assert(0 <= pos && pos <= size);
    if (size >= capacity) reserve();

    for (int i = size; i > pos; i--) {
        data[i] = data[i - 1];
    }
    size++;
    data[pos] = obj;
}

template <typename T>
void MyVector<T>::erase(int pos) {
    assert(0 <= pos && pos < size);
    for (int i = pos; i < size; i++) {
        data[i] = data[i + 1];
    }
    size--;
}

#endif //INC_20S_3353_PA01_MYVECTOR_H

class BestFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;

public:
    BestFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

class FirstFit: public Allocator {
private:
    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    MyVector<pair<size_t, size_t>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    MyVector<size_t> followMemSize;
public:
    FirstFit();
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {
        cout << "[";
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.getSize()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

class RandomFit: public Allocator {
public:
    void* getMem(size_t size);
    void freeMem(void*);
    void debug() {};
};

size_t intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}

BestFit::BestFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* BestFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void BestFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

FirstFit::FirstFit() {
    // the entire memory we have (256MB)
    emptyIntervals.pushBack({0, MEMORY - 4});

    // fill the vector with 0
    for (size_t i = 0; i * 4 < MEMORY; i++) {
        followMemSize.pushBack(0);
    }
}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (int i = 0; i < emptyIntervals.getSize(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(i);
            }

            // mark followMemSize
            followMemSize[validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}

void FirstFit::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty interval list0
    pair<size_t, size_t> newInterval = {pos, pos + size - 4};

    int addedPosition = -1;

    // find the position to add
    if (newInterval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(0, newInterval);
        addedPosition = 0;
    }
    else {
        for (int i = 0; i < emptyIntervals.getSize(); i++) {
            if (emptyIntervals[i].second < newInterval.first) {
                // add after this interval

                if (newInterval.first == emptyIntervals[i].second + 4) {
                    // merge newInterval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newInterval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(i + 1, newInterval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.getSize()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(addedPosition + 1);
    }

    followMemSize[pos] = 0;
}

void* RandomFit::getMem(size_t size) {
    return startMem;
}

void RandomFit::freeMem(void* p) {
    free(p);
}

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    static FirstFit firstFit;
    static BestFit bestFit;
    static RandomFit randomFit;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;
FirstFit AllocatorSingleton::firstFit = FirstFit();
BestFit AllocatorSingleton::bestFit = BestFit();
RandomFit AllocatorSingleton::randomFit = RandomFit();

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = &firstFit;
                break;
            case BEST_FIT:
                alloc = &bestFit;
                break;
            case RANDOM_FIT:
                alloc = &randomFit;
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

#define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


#include <bits/stdc++.h>

#define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

void update(vector<int> used, int &maxVal) {
    while (used[maxVal]) maxVal--;
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    int maxVal = n;

    int r;
    cin >> r;
    used[r] = 1;
    update(used, maxVal);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            update(used, maxVal);
        }
        else {
            edges.pb({last, maxVal});
            used[maxVal] = 1;
            update(used, maxVal);
        }
        last = x;
    }
    edges.pb({last, maxVal});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


#include <bits/stdc++.h>

template <class T>
class STLAllocator {
public:
    typedef T value_type;

    T* allocate(std::size_t n) {
        return static_cast<T*>(std::malloc(n*sizeof(T)));
    }

    void deallocate(T* p, std::size_t)noexcept {
        std::free(p);
    }

};

//
// Created by cuom1999 on 2/4/20.
//

using namespace std;

class Allocator {
protected:
    static const size_t MEMORY = 100<<20; // 256MB
    void* startMem = malloc(MEMORY);

    // 1. emptyIntervals contains all empty segments, each
    //    segment is a pair [l, r]
    // 2. the segments are kept in increasing order
    // 3. two consecutive segments in the list are not
    //    consecutive, i.e if [l, r] and [u, v] are adjacent
    //    then u - r > 4
    vector<pair<size_t, size_t>, STLAllocator<pair<size_t, size_t>>> emptyIntervals;

    // followMemSize[i] = length of using segment having
    // start position (i * 4)
    vector<size_t, STLAllocator<size_t>> followMemSize;

    size_t intervalLen(const pair<size_t, size_t> &p);

public:
    Allocator();

    void* getStartMem() {return startMem;}
    virtual void* getMem(size_t size) = 0;
    virtual void freeMem(void* p);

    void debug() {
        cout << "[";
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            cout << "(" << emptyIntervals[i].first << ", " << emptyIntervals[i].second << ")";
            if (i + 1 != emptyIntervals.size()) cout << ", ";
        }
        cout << "]" << endl;
    }
};

//
// Created by cuom1999 on 2/11/20.
//

Allocator::Allocator() {
    emptyIntervals.push_back({0, MEMORY - 4});
    followMemSize.resize(MEMORY / 4);
}

void Allocator::freeMem(void* p) {
    size_t pos = (uint8_t*) p - (uint8_t*) startMem;
    size_t size = followMemSize[pos / 4];

    // add [p, p + len] to the empty size_terval list0
    pair<size_t, size_t> newsize_terval = {pos, pos + size - 4};

    size_t addedPosition = -1;

    // find the position to add
    if (newsize_terval.second < emptyIntervals[0].first) {
        emptyIntervals.insert(emptyIntervals.begin(), newsize_terval);
        addedPosition = 0;
    }
    else {
        for (size_t i = 0; i < emptyIntervals.size(); i++) {
            if (emptyIntervals[i].second < newsize_terval.first) {
                // add after this size_terval

                if (newsize_terval.first == emptyIntervals[i].second + 4) {
                    // merge newsize_terval with the one before
                    addedPosition = i;
                    emptyIntervals[i].second = newsize_terval.second;
                }
                else {
                    addedPosition = i + 1;
                    emptyIntervals.insert(emptyIntervals.begin() + i + 1, newsize_terval);
                }
                break;
            }
        }
    }

    // merge newInterval with the one after it if needed
    if (addedPosition + 1 < emptyIntervals.size()
        && emptyIntervals[addedPosition].second + 4
           == emptyIntervals[addedPosition + 1].first) {

        emptyIntervals[addedPosition].second = emptyIntervals[addedPosition + 1].second;
        emptyIntervals.erase(emptyIntervals.begin() + addedPosition + 1);
    }

    followMemSize[pos / 4] = 0;
}

size_t Allocator::intervalLen(const pair<size_t, size_t> &p) {
    return (size_t) (p.second - p.first + 4);
}//
// Created by cuom1999 on 2/5/20.
//

using namespace std;

class FirstFit: public Allocator {
public:
    FirstFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

FirstFit::FirstFit() {

}

void* FirstFit::getMem(size_t size) {
    int validPos = -1;

    for (size_t i = 0; i < emptyIntervals.size(); i++) {
        if (intervalLen(emptyIntervals[i]) >= size) {
            // this is the valid empty segment
            validPos = emptyIntervals[i].first;

            // modify the emptyIntervals
            emptyIntervals[i].first += size;
            if (emptyIntervals[i].first > emptyIntervals[i].second) {
                emptyIntervals.erase(emptyIntervals.begin() + i);
            }

            // mark followMemSize
            followMemSize[(size_t) validPos / 4] = size;
            break;
        }
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    return (uint8_t*) startMem + (size_t) validPos;
}
//
// Created by cuom1999 on 2/5/20.
//

using namespace std;

class BestFit: public Allocator {
public:
    BestFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

BestFit::BestFit() {
}

void* BestFit::getMem(size_t size) {
    int bestPos = -1;
    size_t bestSize = 0;

    // find the bestPos - best fit block
    for (size_t i = 0; i < emptyIntervals.size(); i++) {
        size_t currLen = intervalLen(emptyIntervals[i]);
        if (currLen >= size) {
            // check if this is smaller than the current best block
            if (bestPos == -1 || bestSize > currLen) {
                bestSize = currLen;
                bestPos = i;
            }
        }
    }

    if (bestPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    size_t memPosition = emptyIntervals[bestPos].first;

    // modify the emptyIntervals
    emptyIntervals[bestPos].first += size;
    if (emptyIntervals[bestPos].first > emptyIntervals[bestPos].second) {
        emptyIntervals.erase(emptyIntervals.begin() + bestPos);
    }

    followMemSize[memPosition / 4] = size;

    return (uint8_t*) startMem + (size_t) memPosition;
}
//
// Created by cuom1999 on 2/5/20.
//

class RandomFit: public Allocator {
public:
    RandomFit();
    void* getMem(size_t size);
};

//
// Created by cuom1999 on 2/5/20.
//

RandomFit::RandomFit() {

}

// In this Fit, we do the similar traversal as FirstFit but
// start at a random position
// First, choose a random interval, then travel to left and right at the
// same time to find the best interval that >= size
void* RandomFit::getMem(size_t size) {
    srand(time(0));

    size_t startPos = rand() % emptyIntervals.size(); // random startPos
    size_t leftPtr = startPos;
    size_t rightPtr = startPos;
    int validPos = -1;

    // check if startPos is big enough
    if (intervalLen(emptyIntervals[startPos]) >= size) {
        validPos = startPos;
    }

    // loop to find the first interval
    while (validPos == -1) {
        bool canContinue = false;

        if (rightPtr < emptyIntervals.size()) {
            canContinue = true;
            rightPtr++;
            if (intervalLen(emptyIntervals[rightPtr]) >= size) {
                validPos = rightPtr;
                break;
            }
        }

        if (leftPtr > 0) {
            canContinue = true;
            leftPtr--;
            if (intervalLen(emptyIntervals[leftPtr]) >= size) {
                validPos = leftPtr;
                break;
            }
        }
        if (!canContinue) break;
    }

    if (validPos == -1) {
        cout << "Run out of memory" << endl;
        exit(1);
    }

    size_t memPosition = emptyIntervals[validPos].first;

    // modify the emptyIntervals
    emptyIntervals[validPos].first += size;
    if (emptyIntervals[validPos].first > emptyIntervals[validPos].second) {
        emptyIntervals.erase(emptyIntervals.begin() + validPos);
    }

    followMemSize[memPosition / 4] = size;

    return (uint8_t*) startMem + (size_t) memPosition;
}
//
// Created by cuom1999 on 2/4/20.
//

class AllocatorSingleton {
private:
    enum Strategy {
        FIRST_FIT,
        BEST_FIT,
        RANDOM_FIT
    };

    static Allocator* alloc;
    static Strategy strategy;
    AllocatorSingleton() = default;

public:

    static void useFirstFit();
    static void useBestFit();
    static void useRandomFit();

    static Allocator* getAllocator();
};

// initialize all static members
Allocator* AllocatorSingleton::alloc = nullptr;
AllocatorSingleton::Strategy AllocatorSingleton::strategy = AllocatorSingleton::FIRST_FIT;

void AllocatorSingleton::useFirstFit() {
    strategy = FIRST_FIT;
}

void AllocatorSingleton::useBestFit() {
    strategy = BEST_FIT;
}

void AllocatorSingleton::useRandomFit() {
    strategy = RANDOM_FIT;
}

Allocator* AllocatorSingleton::getAllocator() {
    if (alloc == nullptr) {
        switch(strategy) {
            case FIRST_FIT:
                alloc = (FirstFit*) malloc(sizeof(FirstFit));
                new (alloc) FirstFit();
                break;
            case BEST_FIT:
                alloc = (BestFit*) malloc(sizeof(BestFit));
                new (alloc) BestFit();
                break;
            case RANDOM_FIT:
                alloc = (RandomFit*) malloc(sizeof(RandomFit));
                new (alloc) RandomFit();
                break;
            default:
                throw runtime_error("You have to init strategy");
        }
    }
    return alloc;
}

//
// Created by cuom1999 on 2/5/20.
//

void* operator new(size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void* operator new[](size_t size) {
    Allocator *a = AllocatorSingleton::getAllocator();
    return a->getMem(size);
}

void operator delete(void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

void operator delete[](void* p) noexcept {
    Allocator *a = AllocatorSingleton::getAllocator();
    a->freeMem(p);
}

using namespace std;

 #define ld long double
#define sf scanf
#define pf printf
#define pb push_back
#define PI ( acos(-1.0) )
#define IN freopen("input.txt","r",stdin)
#define OUT freopen("output.txt","w",stdout)
#define FOR(i,a,b) for(int i=a ; i<=b ; i++)
#define FORD(i,a,b) for(int i=a ; i>=b ; i--)
#define INF 1000000000
#define ll long long int
#define eps (1e-8)
#define sq(x) ( (x)*(x) )
#define all(x) x.begin(),x.end()
#define flog2(n) 64 - __builtin_clzll(n) - 1
#define popcnt(n) __builtin_popcountll(n)

using namespace std;

typedef pair < int, int > pii;
typedef pair < ll, ll > pll;

// void update(vector<int> used, int &maxVal) {
//     while (used[maxVal] && maxVal) maxVal--;
// }
int main()
{
    AllocatorSingleton::useRandomFit();
    ios::sync_with_stdio(0);
    cin.tie(NULL);

    int n;
    cin >> n;
    vector<int> used(n + 1);
    // int maxVal = n;
    set<int> s;
    FOR (i, 1, n) s.insert(i);

    int r;
    cin >> r;
    used[r] = 1;
    // update(used, maxVal);
    s.erase(r);

    vector<pair<int, int>> edges;
    int last = r;

    FOR (i, 1, n - 2) {
        int x;
        cin >> x;
        if (!used[x]) {
            edges.pb({last, x});
            used[x] = 1;
            s.erase(x);
            // update(used, maxVal);
        }
        else {
            int maxVal = *(--s.end());

            edges.pb({last, maxVal});
            used[maxVal] = 1;
            // update(used, maxVal);
            s.erase(maxVal);
        }
        last = x;
    }
    edges.pb({last, *(s.begin())});

    cout << r << '\n';
    for (auto e: edges) {
        cout << e.first << " " << e.second << '\n';
    }

    return 0;
}


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

int main()
{
    long long int n,i;
    cin>>n;

    long long int degree[n+1];
    for(i=0;i<=n;i++)
        degree[i]=1;

    vector<long long int> v;
    for(i=0;i<n-1;i++)
    {
        long long int y;
        cin>>y;
        v.push_back(y);
        degree[y]++;
    }

    long long int root=v[0];
    vector<pair<long long int,long long int> > ans;

    set<long long int> s;
    set<long long int>::iterator it;

    for(i=1;i<=n;i++)
    {
        if(degree[i]==1)
            s.insert(i);
    }

    long long int idx=n-2;

    while(idx>=0)
    {
        vector<long long int> temp;

        for(it=s.begin();it!=s.end();it++)
        {
            ans.push_back({*it,v[idx]});
            degree[*it]--;
            degree[v[idx]]--;
            if(degree[v[idx]]==1)
                temp.push_back(v[idx]);
            idx--;
        }

        s.clear();
        long long int si=temp.size();
        for(i=0;i<si;i++)
            s.insert(temp[i]);
    }

    cout<<root<<"\n";
    for(i=0;i<n-1;i++)
        cout<<ans[i].first<<" "<<ans[i].second<<"\n";
}


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

int main()
{
    long long int n,i;
    cin>>n;

    long long int degree[n+1];
    for(i=0;i<=n;i++)
        degree[i]=1;

    vector<long long int> v;
    for(i=0;i<n-1;i++)
    {
        long long int y;
        cin>>y;
        v.push_back(y);
        degree[y]++;
    }

    long long int root=v[0];
    vector<pair<long long int,long long int> > ans;

    set<long long int> s;

    for(i=1;i<=n;i++)
    {
        if(degree[i]==1)
            s.insert(i);
    }

    long long int idx=n-2;

    while(idx>=0)
    {
        long long int temp=*s.begin();
        ans.push_back({temp,v[idx]});
        degree[temp]--;
        degree[v[idx]]--;
        if(degree[v[idx]]==1)
            s.insert(v[idx]);
        s.erase(temp);
        idx--;

    }

    cout<<root<<"\n";
    for(i=0;i<n-1;i++)
        cout<<ans[i].first<<" "<<ans[i].second<<"\n";
}


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

int main()
{
    long long int n,i;
    cin>>n;

    vector<long long int> v;
    set<long long int,greater<long long int> > available;

    for(i=1;i<=n;i++)
        available.insert(i);

    for(i=0;i<n-1;i++)
    {
        long long int y;
        cin>>y;
        v.push_back(y);
    }

    long long int root=v[0];
    available.erase(v[0]);

    vector<pair<long long int,long long int> > ans;

    for(i=0;i<n-2;i++)
    {
        if(available.find(v[i+1])!=available.end())
        {
            ans.push_back({v[i],v[i+1]});
            available.erase(v[i+1]);
        }
        else
        {
            ans.push_back({v[i],*available.begin()});
            available.erase(available.begin());
        }
    }

    ans.push_back({v[n-2],*available.begin()});
    cout<<root<<"\n";
    for(i=0;i<n-1;i++)
        cout<<ans[i].first<<" "<<ans[i].second<<"\n";
}


/*/ Author: kal013 /*/
//#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
#define int long long
#define ll long long
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<pii,int> ppi;
typedef vector<pii> vpi;
typedef priority_queue<ppi> max_heap_ppi;
#define For(i,n) for(int i=0;i<(int)n;i++)
#define Rev(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,n) for(int i=1;i<=n;++i)
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define endl "\n"
#define d0(x) cout<<(x)<<" "
#define d1(x) cout<<(x)<<endl
#define d2(x,y) cout<<(x)<<" "<<(y)<<endl
#define d3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define d4(a,b,c,d) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<endl
#define d5(a,b,c,d,e) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<" "<<(e)<<endl
#define d6(a,b,c,d,e,f) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<" "<<(e)<<" "<<(f)<<endl
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define all(v) (v).begin(),(v).end()
#define sz(v) (v).size()

template<class T> ostream& operator<<(ostream &os, vector<T> V) {
    os << "[ ";
    for(auto v : V) os << v << " ";
    return os << "]";
}
template<class T> ostream& operator<<(ostream &os, set<T> S){
    os << "{ ";
    for(auto s:S) os<<s<<" ";
    return os<<"}";
}
template<class L, class R> ostream& operator<<(ostream &os, pair<L,R> P) {
    return os << "(" << P.first << "," << P.second << ")";
}
template<class L, class R> ostream& operator<<(ostream &os, map<L,R> M) {
    os << "{ ";
    for(auto m:M) os<<"("<<m.F<<":"<<m.S<<") ";
    return os<<"}";
}

#define TRACE
#ifdef TRACE
    #define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
    template <typename Arg1>
    void __f(const char* name, Arg1&& arg1){
        cerr << name << " : " << arg1 << endl;
    }
    template <typename Arg1, typename... Args>
    void __f(const char* names, Arg1&& arg1, Args&&... args){
        const char* comma = strchr(names + 1, ',');
        cerr.write(names, comma - names) << " : " << arg1<<" | ";
        __f(comma+1, args...);
    }
#else
    #define trace(...)
#endif
const int maxn=1e6+100;
const int MaxN=1e5+100;
const int mod=1e9+7;
#ifdef int
const int INF=1e16;
#else
const int INF=1e9;
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;
// erase,insert same as normal set
#endif

inline int fast_expo(int base,int power,int modulo=mod){
    base%=modulo;
    if (base<0) base+=modulo;
    ll x=base,cnt=power,ans=1;
    while(cnt){
        if (cnt&1) ans=(ans*x)%modulo;
        x=(x*x)%modulo;
        cnt>>=1;
    }
    // int tmp=ans;
    return ans;
}
inline int inv(int base,int modulo=mod){
    return fast_expo(base,modulo-2,modulo);
}

/*/-----------------------------Code begins----------------------------------/*/

int deg[maxn],x[maxn];

int y[maxn];
bool vis[maxn];
bool done[maxn];

void solve(){
	int n;
	cin>>n;
	int root;
	For(i,n-1){
		cin>>x[i];
		++deg[x[i]];
	}
	root=x[0];

	Rep(i,n){
		if (i!=root) ++deg[i];
	}
	done[root]=1;
	int z=0;

	vi stk;
	for(int i=n;i>=1 && z<=n-1;){
		if (done[i]) {--i;continue;}
		if (vis[x[z]]){
			y[z-1]=i;
			vis[i]=1;
			done[i]=1;
			// while(!stk.empty()){
			// 	auto T=stk.back();

			// 	stk.pop_back();
			// 	// vis[T]=0;
			// 	if (x[T]==x[z]) break;
			// }

			// stk.pb(z);
			vis[x[z]]=1;
			--i;

		}
		else if (x[z]==i){
			y[z-1]=i;
			done[i]=1;
			// stk.pb(z);
			vis[x[z]]=1;
			--i;
		}
		else{
			if (!stk.empty()){
				y[z-1]=x[z];
				done[x[z]]=1;
			}
			// stk.pb(z);
			vis[x[z]]=1;
		}

		++z;
	}
	for(int i=1;i<=n;++i){
		if (!vis[i]) y[n-2]=i;
	}
	cout<<root<<endl;

	For(i,n-1){
		cout<<x[i]<<" "<<y[i]<<endl;
	}

}
signed main(){
    // Use "set_name".max_load_factor(0.25);"set_name".reserve(512); with unordered set
    // Uncomment codechef for large input files. Doesn't work on codeforces.

    fio;
    int t=1;
    // cin>>t;
    while(t--) {
        solve();
    }
}


/*/ Author: kal013 /*/
//#pragma GCC optimize ("O3")
#include <bits/stdc++.h>
#include <cstdio>
using namespace std;
#define int long long
#define ll long long
typedef vector<int> vi;
typedef pair<int,int> pii;
typedef pair<pii,int> ppi;
typedef vector<pii> vpi;
typedef priority_queue<ppi> max_heap_ppi;
#define For(i,n) for(int i=0;i<(int)n;i++)
#define Rev(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,n) for(int i=1;i<=n;++i)
#define F first
#define S second
#define pb push_back
#define mp make_pair
#define endl "\n"
#define d0(x) cout<<(x)<<" "
#define d1(x) cout<<(x)<<endl
#define d2(x,y) cout<<(x)<<" "<<(y)<<endl
#define d3(x,y,z) cout<<(x)<<" "<<(y)<<" "<<(z)<<endl
#define d4(a,b,c,d) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<endl
#define d5(a,b,c,d,e) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<" "<<(e)<<endl
#define d6(a,b,c,d,e,f) cout<<(a)<<" "<<(b)<<" "<<(c)<<" "<<(d)<<" "<<(e)<<" "<<(f)<<endl
#define fio ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
#define all(v) (v).begin(),(v).end()
#define sz(v) (v).size()

template<class T> ostream& operator<<(ostream &os, vector<T> V) {
    os << "[ ";
    for(auto v : V) os << v << " ";
    return os << "]";
}
template<class T> ostream& operator<<(ostream &os, set<T> S){
    os << "{ ";
    for(auto s:S) os<<s<<" ";
    return os<<"}";
}
template<class L, class R> ostream& operator<<(ostream &os, pair<L,R> P) {
    return os << "(" << P.first << "," << P.second << ")";
}
template<class L, class R> ostream& operator<<(ostream &os, map<L,R> M) {
    os << "{ ";
    for(auto m:M) os<<"("<<m.F<<":"<<m.S<<") ";
    return os<<"}";
}

#define TRACE
#ifdef TRACE
    #define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
    template <typename Arg1>
    void __f(const char* name, Arg1&& arg1){
        cerr << name << " : " << arg1 << endl;
    }
    template <typename Arg1, typename... Args>
    void __f(const char* names, Arg1&& arg1, Args&&... args){
        const char* comma = strchr(names + 1, ',');
        cerr.write(names, comma - names) << " : " << arg1<<" | ";
        __f(comma+1, args...);
    }
#else
    #define trace(...)
#endif
const int maxn=1e6+100;
const int MaxN=1e5+100;
const int mod=1e9+7;
#ifdef int
const int INF=1e16;
#else
const int INF=1e9;
//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//using namespace __gnu_pbds;
//#define ordered_set tree<int, null_type,less<int>, rb_tree_tag,tree_order_statistics_node_update>
// find_by_order(k)  returns iterator to kth element starting from 0;
// order_of_key(k) returns count of elements strictly smaller than k;
// erase,insert same as normal set
#endif

inline int fast_expo(int base,int power,int modulo=mod){
    base%=modulo;
    if (base<0) base+=modulo;
    ll x=base,cnt=power,ans=1;
    while(cnt){
        if (cnt&1) ans=(ans*x)%modulo;
        x=(x*x)%modulo;
        cnt>>=1;
    }
    // int tmp=ans;
    return ans;
}
inline int inv(int base,int modulo=mod){
    return fast_expo(base,modulo-2,modulo);
}

/*/-----------------------------Code begins----------------------------------/*/

int deg[maxn],x[maxn];

int y[maxn];
bool vis[maxn];
bool done[maxn];

void solve(){
	int n;
	cin>>n;
	int root;
	For(i,n-1){
		cin>>x[i];
		++deg[x[i]];
	}
	root=x[0];

	Rep(i,n){
		if (i!=root) ++deg[i];
	}
	done[root]=1;
	int z=0;

	vi stk;
	for(int i=n;i>=1 && z<=n-1;){
		if (done[i]) {--i;continue;}
		if (vis[x[z]]){
			y[stk.back()]=i;
			vis[i]=1;
			done[i]=1;
			while(!stk.empty()){
				auto T=stk.back();

				stk.pop_back();
				// vis[T]=0;
				if (x[T]==x[z]) break;
			}

			stk.pb(z);
			vis[x[z]]=1;
			--i;

		}
		else if (x[z]==i){
			y[stk.back()]=i;
			done[i]=1;
			stk.pb(z);
			vis[x[z]]=1;
			--i;
		}
		else{
			if (!stk.empty()){
				y[stk.back()]=x[z];
				done[x[z]]=1;
			}
			stk.pb(z);
			vis[x[z]]=1;
		}

		++z;
	}
	for(int i=1;i<=n;++i){
		if (!vis[i]) y[n-2]=i;
	}
	cout<<root<<endl;

	For(i,n-1){
		cout<<x[i]<<" "<<y[i]<<endl;
	}

}
signed main(){
    // Use "set_name".max_load_factor(0.25);"set_name".reserve(512); with unordered set
    // Uncomment codechef for large input files. Doesn't work on codeforces.

    fio;
    int t=1;
    // cin>>t;
    while(t--) {
        solve();
    }
}


/*
ID : omarmuh1
PROG : test
LANG : C++11
*/

#include "bits/stdc++.h"
#include "ext/pb_ds/assoc_container.hpp"

#define mp make_pair
#define pb push_back
#define ppb pop_back
#define db puts("*****")
#define mid(x , y) ((x+y)>>1)
#define ff first
#define ss second
#define all(x)	x.begin(),x.end()
#define ll long long
#define sqr(x)	((x)*(x))
#define pii pair <int , int>
#define sz(x) int(x.size())
#define tr(it , c) for(__typeof(c.begin()) it = (c.begin()); it != (c.end()); it++)
#define y1 you_made_my_day

using namespace std;
using namespace __gnu_pbds;

const int N = 2e5+7;
const int MOD = 1e9+7;

template<class T> bool umin(T& a, T b) { if(a > b){ a = b;return 1;}return 0;}
template<class T> bool umax(T& a, T b) { if(a < b){ a = b;return 1;}return 0;}
template<class T> bool umod(T& a) { while(a < 0) a += MOD; a %= MOD; return 1;}
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> omar;

//	freopen("file.in" , "r" , stdin);
//	freopen("file.out" , "w" , stdout);

set<pii> setik;
int n, arr[N], cn, d[N], vis[N];
vector<pii> v;
vector<int> E[N];
bool ok = true;

void dfs(int x, int y){
    if(vis[x]){
        ok = false;
        return;
    }
    vis[x] = 1;
    for(int i : E[x])
        if(i != y)
            dfs(i, x);
}

int main(){
    scanf("%d", &n);
    for(int i=1; i<n; i++)
        scanf("%d", &arr[i]), d[arr[i]] = 1;
    for(int i=1; i<=n; i++)
        if(!d[i])
            setik.insert({i, i});
    cn = n-1;
    while(cn > 0 && sz(setik) > 0){
        pii tr = *setik.begin(); setik.erase(tr);
        v.pb({tr.ss, arr[cn]});
        setik.insert({max(tr.ff, arr[cn]), arr[cn]});
        E[tr.ss].pb(arr[cn]);
        E[arr[cn]].pb(tr.ss);
        cn--;
    }
    dfs(arr[1], 0);
    if(!ok)
        return 0 * printf("-1\n");
    ok = true;
    for(int i=1; i<=n; i++)
        if(!vis[i])
            ok = false;
    if(!ok)
        return 0 * printf("-1\n");

    printf("%d\n", arr[1]);
    for(pii i : v)
        printf("%d %d\n", i.ff, i.ss);

	return 0;
}


/*
ID : omarmuh1
PROG : test
LANG : C++11
*/

#include "bits/stdc++.h"
#include "ext/pb_ds/assoc_container.hpp"

#define mp make_pair
#define pb push_back
#define ppb pop_back
#define db puts("*****")
#define mid(x , y) ((x+y)>>1)
#define ff first
#define ss second
#define all(x)	x.begin(),x.end()
#define ll long long
#define sqr(x)	((x)*(x))
#define pii pair <int , int>
#define sz(x) int(x.size())
#define tr(it , c) for(__typeof(c.begin()) it = (c.begin()); it != (c.end()); it++)
#define y1 you_made_my_day

using namespace std;
using namespace __gnu_pbds;

const int N = 2e5+7;
const int MOD = 1e9+7;

template<class T> bool umin(T& a, T b) { if(a > b){ a = b;return 1;}return 0;}
template<class T> bool umax(T& a, T b) { if(a < b){ a = b;return 1;}return 0;}
template<class T> bool umod(T& a) { while(a < 0) a += MOD; a %= MOD; return 1;}
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> omar;

//	freopen("file.in" , "r" , stdin);
//	freopen("file.out" , "w" , stdout);

set<pii> setik;
int n, arr[N], cn, d[N], vis[N], mx[N];
vector<pii> v;
vector<int> E[N];
bool ok = true;

void dfs(int x, int y){
    if(vis[x]){
        ok = false;
        return;
    }
    vis[x] = 1;
    for(int i : E[x])
        if(i != y)
            dfs(i, x);
}

int main(){
    scanf("%d", &n);
    for(int i=1; i<n; i++)
        scanf("%d", &arr[i]), d[arr[i]]++, mx[arr[i]] = arr[i];
    for(int i=1; i<=n; i++)
        if(!d[i])
            setik.insert({i, i});
    cn = n-1;
    while(cn > 0 && sz(setik) > 0){
        pii tr = *setik.begin(); setik.erase(tr);
        d[arr[cn]]--;
        umax(mx[arr[cn]], tr.ff);
        if(d[arr[cn]] == 0)
            setik.insert({mx[arr[cn]], arr[cn]});
        v.pb({tr.ss, arr[cn]});
        E[tr.ss].pb(arr[cn]);
        E[arr[cn]].pb(tr.ss);
        cn--;
    }
    dfs(arr[1], 0);
    if(!ok)
        return 0 * printf("-1\n");
    ok = true;
    for(int i=1; i<=n; i++)
        if(!vis[i])
            ok = false;
    if(!ok)
        return 0 * printf("-1\n");

    printf("%d\n", arr[1]);
    for(pii i : v)
        printf("%d %d\n", i.ff, i.ss);

	return 0;
}


#include <iostream>
#include <cmath>
using namespace std;
int main()
{
	double a, b, all;
	scanf("%lf%lf%lf", &a, &b, &all);
	double Ttime = 0, Ts = 0;
	double alltime;
	/*
	while (Ttime < a)
		Ttime += b;
	*/
	Ttime = (ceil)(a / b);
	Ttime *= b;
	Ts = a + (Ttime - a) / 2;
	alltime = (long long int)(all / Ts) * Ttime;
	all -= (long long int)(all / Ts) * Ts;
	if (all <= a)
		alltime += all;
	else
	{
		alltime += a;
		all -= a;
		alltime += all * 2;
	}
	printf("%.1lf\n", alltime);
}


//                                                                                ..XQZKSUI25IK:
//                                                                                .iiPK5uU122L..
//                                .                                                                                :jEKIIU5XDPj:
//                              .::.                                                                                :XPESSI55qPL
//                             iJ77vvrr                                                                                :7PPXIIIXqgjr
//                            :rrrr7r7r.                                                                                iudPKq5SSPE7:
//                           .srrirri..                                         ...:i:iv7:i:i:i:...                             UUKSbXSIXqZbD7.
//                           .7riri7i..                                ..i7LqZQBBBBBBBBBBBQBBBQBBBQBZKUs::.                        .JKPX25IKKEP.
//                         .:.7rrir7i                             :72IgBBBBBBQBBBQBBBQBBBBBBBBBBBBBBBBBBBQQSvr7:.                    :IUSUI1IIqdd
//                         ...rrirrvi .                        .rEBBBBBBQBBBBBBBBBBBBBBBQBBBBBBBBBBBBBBBBBBBBBBBEr.                    i21u2U2UXqMv.
//                         :rrrirrr:.                       .vSQBBBBBBBBBBBBBBBBBBBBBQBBBBBBBBBBBBBBBQBQBBBBBQBBBQBIv.                vUdYJ152IUSX5X:
//                         :vrirrri..                    Y2MBBBBBBBBBBBBBBQBQg5qqXv777777777777J2PMQBBBBQBBBBBBBBBBBBB5ri            rQBQBBqKPXX25SdqI.
//                        .:7rrirr7                   r2ZBBQBBBBBBBBBBBKur:..                     ...:Y1PZBBBBBBBQBBBBBBBEY.       .IZBBBBB.:udbPSSIqbXP.
//                       .v7rrirr7v                 uEBBBBBBBBBBQE1vi..                                  ..JdBBBBBBBBBQBBBBB1i   .vsBBQBBgU    :iZqXSPgB:
//                       .vrrrriri:             . 2dBBBBBBBQBBMYi                                            ..7EQBQBBBBBBBBBBL: :ZbBBBMX:.      :Sdbd7i.
//                       .7ririr7.              YvQBQBBBBBBBgsi.                                     .          :LuQBBBBBBBBBBMPrsPZBBBX:         :7rr
//                       .7rrrrrs.            7JBQBBBBBBBXIi                                                       .vQBBBBBQBBBBBBQQBZ7.
//                      :rrrirrrr.          :jBBQBBBBBQ5r                       ::.      ..                          .rXPBBBBBBBBBBBQ7
//                      L7rirr7:.         .vgBBBBBBBdY.                      .rrgK.    .rKqi:.                           2QBBBBBBBBBBu
//                      r7irir7:.        .rBBBBBQBbU                        rJMgK1   .:irYLYUQJ.                          .7QBBBBBQBBBP7
//                    ::7rrrrrv:        :qQBBQBBKK       ...        . .:7Jr7dIuj17   i7i.   .rv7:.                          rPBBBBBBBQBQb.
//                    .:rrirr77:       .rBBBBBBB..                   .iZBBRMBQZdri   iii:i:i.  iir                            qBBBBBBBBBB:
//                    77rrrrri:        sdBBBBBXs                    v5BBBBBBBQMZ7i    .2PSqgQQQ5i.                            :vBBBBBBBBBd5
//                    r7irirr.       riBBBBBBZ.                    .iLi::r77:iirii     ..:..:rUgr.                             .ugBBQBQBBBB:i
//                  ..rrririi:.     .ZqBBBBQj:                                .....         .                                    iBDBBBBBBBSd:
//                  :Lrrir:7v1QK7. .iBMBBBQu.                                ...     .                                            :rBBBBBBBBBL.
//                  :vriri:IQRBBBPJisBBBBBP:.                             ..7.          .                                           gQBBBBBQBdU
//                 .:7irii.QBBBBBBQEZBBBBE7                               ..:r77r:    . ....                                        rPBBBBQBBBB.
//                 .:rririiKQQBBBBBBBBBBBr:                            ...   .LLQEvvsrr.. ...                                        iBBBBBBBBBri
//                .iirirrri. .iYUQBBBBBBgi.                           .i..      :ir77:.    ....                                      .UgQBBBBBBd1
//              . :Yvrrrv:       :1QBBBBb..                         . .:LJ77jsJv:....       ....                                      .IBBBBBBBBB.
//                .7r77vr:        .PQBBBX                           ..  LMQg7v7vri.......i::....                                       7RBBBBBBBBv:
//                 .:rii.          vdBBE1                           .   .7UY....:...... rDRr.                                          .igBQBBBBBXr
//                  .r..           7KBBgu                                 vKBBBBBBqPPjvr7KK. .                                           bBBBBBBBQr
//                                 7bBBg1                                  .BBZZMDMggBBbr    ..                                          IgBBBBBBgv
//                                 .rBQDI:.                                 .        i:    ..                                            .:BQBBBQIi
//                                  .5uQB57                                 . ...                                                          ::v2ri
//                                  .i:bgPv                                 ........
//                                     iUD1
//                                     ..r:.
//
//
//                                             RB.  BQ1X:            rs                                       BR  :BBsK.            r7
//                                          2DSRBQvBM.ij:     BRJBB  BBr        EBi                        qdKgBPjBD:rJ:    :QPKBB  BB:        BB.
//                                            R1L 7B7gB       Bj:B   BB         gBd                          QJs 7BiMB       B7rB   BB         BB.
//                                           2B7BK.SMQ7       Q:iE   B5         vBi                         5BIBP.PPgi       B.I1   Qs         BQ
//                                          ZBKBg iiXQi       BrBB7 rBB         UB                         BBKBU.:vLP:       BKRB  rBu         LB
//                                          .BQi.YEQr2QBBdY   Q. r  QZPB        SB                         .BB:.LZg:XBBBXu   B. i  BLBB        7B
//                                        idBi EIBB:Y. .jUI   B.  .BR  QBr      rB                       iBB::QJBBi7: :s5I.  Bi  :BD  BBr      :B
//                                        :: .Bi QB JBi       Q..dQi    BBQBv   JB:                      :. .Bi SB ZQi      .Bi.QBr    BQBBs   QB:
//                                           PQ 1BB  QB       B...        .r:   KBr                         qd vBB  BB       Q...        :r:   gB:
//
#include <iostream>
using namespace std;
int main()
{
	int a, b, n;
	scanf("%d%d%d", &a, &b, &n);
	int T = b;
	while (T < a)
		T += b;
	//T是周期
	double s = a + (T - a) / 2.0;
	//S是周期完成量
	double sum = (int)(n / T) * s;
	double ans = (int)(n / T) * T;
	if (n - sum != 0)
	{
		if (n - sum <= a)
			ans += n - sum;
		else
			ans += n - a + (n - sum - a) * 2;
	}
	printf("%.1lf\n", ans);
}