#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;
    }
    return gcd(j, i % j);
}

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)); // ???????°???°????¨??????§ a*Y/a*X == b*Y/b*X ????????????????????????????????§?????§??¬?´???°??§?????£????????? 
                    iX /= iGcd;
                    iY /= iGcd;
                }
                double dAngle = 0;
                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));
        }
    }

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

    vector<list<pair<pair<long, long>, double> >::iterator> vzIt;
    vzIt.reserve(lzSortedPnt.size());
    while (!lzSortedPnt.empty()) {
        list<pair<pair<long, long>, double> >::iterator it = lzSortedPnt.begin();
        vzIt.clear();
        do {
            vzIt.push_back(it++);
        } while (it != lzSortedPnt.end() && it->second == vzIt.front()->second);

        if (vzIt.size() > 1) { // ?????£?????????????????????????±??????? 
            pair<long, long> azResultLast[2] = { *(--(--(vzResultPnt.end()))), *(--(vzResultPnt.end())) };
            double aiLastResultDirRev[2] = { azResultLast[0].first - azResultLast[1].first, azResultLast[0].second - azResultLast[1].second };
            double aiNextPntDir0[2] = { vzIt.front()->first.first - azResultLast[1].first, vzIt.front()->first.second - azResultLast[1].second };
            double aiNextPntDir1[2] = { vzIt.back()->first.first  - azResultLast[1].first, vzIt.back()->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) { // vzResultPnt???????????¨???????§?????°?????????????????????????????????????????????????????????? 
                reverse(vzIt.begin(), vzIt.end());
            }
        }

        size_t i = 0;
        for (i = 0; i < vzIt.size(); ++i) {
            while (true) {
                pair<long, long> azResultLast[2] = { *(--(--(vzResultPnt.end()))), *(--(vzResultPnt.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 };
                if (aiLastResultDir[0] * aiNextPntDir[1] - aiLastResultDir[1] * aiNextPntDir[0] < 0) { // ?§?????????¶????????????????????£???????????????????????? 
                    vzResultPnt.pop_back();
                } else {
                    break;
                }
            }
            vzResultPnt.push_back(vzIt[i]->first);
            lzSortedPnt.erase(vzIt[i]);
        }
    }

    vzResultPnt.pop_back(); // ?????????????????????????????????????????§?????? 
    cout << vzResultPnt.size() << "\n";
    size_t i = 0;
    for (i = 0; i < vzResultPnt.size(); ++i) {
        cout << vzResultPnt[i].first << " " << vzResultPnt[i].second << "\n";
    }

    return 0;
}

Measured memory_bytes: 11472