#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <algorithm>
#include <cmath>

using namespace std;

long gcd(long i, long j)
{
    if (i < j) {
        swap(i, j);
    }
    if (j == 0) {
        return i;
    }
    long k = i % j;
    return gcd(j, k);
}

int main()
{
    list<pair<pair<long, long>, double> > lzSortedPnt;
    {
        long n = 0;
        vector<pair<long, long> > vzPnt;
        {
            cin >> n;
            vzPnt.resize(n);
            long i = 0;
            for (i = 0; i < n; ++i) {
                cin >> vzPnt[i].second >> vzPnt[i].first; // y,x???????????°?????? 
            }
            sort(vzPnt.begin(), vzPnt.end()); // ?????????????????§????§????????±???????(first,second?????????????????????????????????????????????) 
            if (n < 2) { // ????????±???????????????????????? 
                cout << n << "\n";
                if (n == 1) {
                    cout << vzPnt[0].second << " " << vzPnt[0].first << "\n";
                }
                return 0;
            }
            for (i = 0; i < n; ++i) {
                swap(vzPnt[i].first, vzPnt[i].second); // ?´??????????????????§x,y????????????????????? 
            }
        }

        vector<pair<pair<double, double>, size_t> > vzValuePnt(n); // ?????¬?????????????????¢?????´??????????????????????????????????????????????????? ((?§?????????¨?????????????????????, ?????????2??????), vzPnt????????????) 
        {
            vzValuePnt[0] = pair<pair<double, double>, size_t>(pair<double, double>(0.0, 0.0), 0); // ??????????????????????????????????????????????¢??????????????????§???index0?????????????????????????????????????????? 
            long i = 1;
            for (i = 1; i < n; ++i) {
                long iX = vzPnt[i].first - vzPnt[0].first;
                long iY = vzPnt[i].second - vzPnt[0].second;
                double dLenSq = (iX * iX) + (iY * iY); // ?????????????????????sqrt?????????????????????????????¨?????????????????????????????§??????0????????§?????????????????? 
                if (iX != 0 && iY != 0) {
                    long iGcd = gcd(abs(iX), abs(iY));
                    iX /= iGcd;
                    iY /= iGcd;
                }
                double dAngle = 0; // FIXME : double????????§?????´?????????????????§?????????(a*Y/a*X==b*Y/b*X???????????????????????????)??????????????????????????¢????????§???????????????????????????????????§????????????????????? 
                if (iX > 0) {
                    dAngle = iY / (double)iX; // 0???20000 (??§?¨??????´??°??§?????????-10000???10000??¨????????????????????????????????????????????????) 
                } else if (iX == 0) {
                    dAngle = 25000; // 25000??????iX==0?????±????????¨???????????¨??????????????? 
                } else {
                    dAngle = 50000 + iY / (double)iX; // 30000???50000 
                }
                vzValuePnt[i] = pair<pair<double, double>, size_t>(pair<double, double>(dAngle, dLenSq), i);
            }
            sort(vzValuePnt.begin(), vzValuePnt.end());
        }

        long i = 0;
        for (i = 0; i < n; ++i) {
            lzSortedPnt.push_back(pair<pair<long, long>, double>(vzPnt[vzValuePnt[i].second], vzValuePnt[i].first.first));
        }
    }

    list<pair<long, long> > lzResultPnt;
    {
        // ?????????2??????????????¶????§£(??\??????1?????\????????´???????????????????????±????????¨????????±??£??????????????§??????2?????\????????????) 
        lzSortedPnt.push_back(lzSortedPnt.front()); // ?????????????????????????????¨???????????¨????????? 
        lzResultPnt.push_back(lzSortedPnt.front().first);
        lzSortedPnt.pop_front();
        lzResultPnt.push_back(lzSortedPnt.front().first);
        lzSortedPnt.pop_front();
    }

    while (!lzSortedPnt.empty()) {
        list<pair<pair<long, long>, double> >::iterator it = lzSortedPnt.begin();
        vector<list<pair<pair<long, long>, double> >::iterator> vzIt;
        vzIt.push_back(it);
        ++it;
        while (it != lzSortedPnt.end()) {
            if (vzIt[0]->second != it->second) { // FIXME (double????????§?????´?????????????????§???????????????????????????????????¢????????§???????????????????????????????????§?????????????????????) 
                break;
            }
            vzIt.push_back(it);
            ++it;
        }
        if (vzIt.size() > 1) {
            // ?????£?????????????????????????±??????? 
            pair<long, long> azResultLast[2] = { *(--(--(lzResultPnt.end()))), *(--(lzResultPnt.end())) };
            double aiLastResultDirRev[2] = { azResultLast[0].first - azResultLast[1].first, azResultLast[0].second - azResultLast[1].second };
            double aiNextPntDir0[2] = { vzIt[0]->first.first - azResultLast[1].first, vzIt[0]->first.second - azResultLast[1].second };
            double aiNextPntDir1[2] = { vzIt[vzIt.size() -1]->first.first - azResultLast[1].first, vzIt[vzIt.size() -1]->first.second - azResultLast[1].second };
            double dAngle0 = atan2(aiLastResultDirRev[0] * aiNextPntDir0[1] - aiLastResultDirRev[1] * aiNextPntDir0[0], aiLastResultDirRev[0] * aiNextPntDir0[0] + aiLastResultDirRev[1] * aiNextPntDir0[1]);
            double dAngle1 = atan2(aiLastResultDirRev[0] * aiNextPntDir1[1] - aiLastResultDirRev[1] * aiNextPntDir1[0], aiLastResultDirRev[0] * aiNextPntDir1[0] + aiLastResultDirRev[1] * aiNextPntDir1[1]);
            if (dAngle0 < 0.0) {
                dAngle0 += 2.0 * 3.14159265358979; // FIXME 
            }
            if (dAngle1 < 0.0) {
                dAngle1 += 2.0 * 3.14159265358979; // FIXME 
            }
            if (dAngle0 > dAngle1) { // ???????§?????°????????????????????????????????????????????????? 
                reverse(vzIt.begin(), vzIt.end());
            }
        }
        size_t i = 0;
        for (i = 0; i < vzIt.size(); ++i) {
            while (true) {
                pair<long, long> azResultLast[2] = { *(--(--(lzResultPnt.end()))), *(--(lzResultPnt.end())) };
                long aiLastResultDir[2] = { azResultLast[1].first - azResultLast[0].first, azResultLast[1].second - azResultLast[0].second };
                long aiNextPntDir[2] = { vzIt[i]->first.first - azResultLast[1].first, vzIt[i]->first.second - azResultLast[1].second };
                {
                    // ?§?????????¶????????????????????£???????????????????????? 
                    long iSign = aiLastResultDir[0] * aiNextPntDir[1] - aiLastResultDir[1] * aiNextPntDir[0];
                    if (iSign < 0) {
                        lzResultPnt.pop_back();
                    } else {
                        break;
                    }
                }
            }
            lzResultPnt.push_back(vzIt[i]->first);
            lzSortedPnt.erase(vzIt[i]);
        }
    }

    lzResultPnt.pop_back(); // ?????????????????????????????????????????§?????? 
    long i = 0;
    size_t n = lzResultPnt.size();
    cout << n << "\n";
    list<pair<long, long> >::iterator it = lzResultPnt.begin();
    for ( ; it != lzResultPnt.end(); ++it) {
        cout << it->first << " " << it->second << "\n";
    }

    return 0;
}

Measured memory_bytes: 11284