#include <algorithm>
#include <array>
#include <assert.h>
#include <bitset>
#include <chrono>
#include <cmath>
#include <complex>
#include <cstring>
#include <functional>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <istream>

#include <map>
#include <math.h>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>

namespace asl
{
    
    template <typename numeric_type>
    class point
    {
    public:
        numeric_type x, y;

        point(numeric_type x = 0, numeric_type y = 0) : x(x), y(y) {}

        bool operator<(const point<numeric_type> &ri) const
        {
            if (x != ri.x)
                return x < ri.x;
            return y < ri.y;
        }

        bool operator==(const point<numeric_type> &ri) const
        {
            return x == ri.x && y == ri.y;
        }

        point<numeric_type> &operator-=(const point<numeric_type> &ri)
        {
            x -= ri.x;
            y -= ri.y;
            return *this;
        }

        point<numeric_type> transpose()
        {
            return {y, x};
        }

        friend point<numeric_type> operator-(const point<numeric_type> &a, const point<numeric_type> &b)
        {
            return point<numeric_type>(a) -= b;
        }

    };

    template <typename numeric_type>
    std::ostream &operator<<(std::ostream &out, const point<numeric_type> &p)
    {
        return out << p.x << " " << p.y;
    }

    template <typename numeric_type>
    std::istream &operator>>(std::istream &is, point<numeric_type> &p)
    {
        return is >> p.x >> p.y;
    }

    template <typename numeric_type>
    numeric_type cross(point<numeric_type> a, point<numeric_type> b)
    {
        return a.x * b.y - a.y * b.x;
    }

    template <typename numeric_type>
    int sign(numeric_type v)
    {
        if (v < 0)
            return -1;
        else if (v > 0)
            return +1;
        else
            return 0;
    }
 
#include <stdint.h>

    template <typename T>
    std::istream &operator>>(std::istream &is, std::vector<T> &vec)
    {
        for (auto &value : vec)
            is >> value;
        return is;
    }

} 

#include <experimental/optional>

namespace asl
{
    template <typename numeric_type>
    using polygon = std::vector<point<numeric_type>>;

    template <typename numeric_type>
    polygon<numeric_type> convex_hull(std::vector<point<numeric_type>> cloud, bool allow_collinear = false, bool ccw = false)
    {
        int n = cloud.size(), k;
        std::vector<point<numeric_type>> ch(2 * n);

        sort(cloud.begin(), cloud.end());

        for (int i = k = 0; i < n; ch[k++] = cloud[i++])
            while (k > 1 && sign(cross(ch[k - 1] - ch[k - 2], cloud[i] - ch[k - 2])) >= int(allow_collinear))
                --k;

        for (int i = n - 2, t = k; i >= 0; ch[k++] = cloud[i--])
            while (k > t && sign(cross(ch[k - 1] - ch[k - 2], cloud[i] - ch[k - 2])) >= int(allow_collinear))
                --k;

        ch.resize(k - (k > 1));

        if (ccw)
        {
            std::reverse(ch.begin() + 1, ch.end());
        }

        return ch;
    }

    template <typename numeric_type>
    std::vector<int> arg_convex_hull(const std::vector<point<numeric_type>> &cloud, bool allow_collinear = false, bool ccw = false)
    {
        int n = cloud.size(), k;
        std::vector<int> ch(2 * n);

        std::vector<int> o(n);
        std::iota(o.begin(), o.end(), 0);
        std::sort(o.begin(), o.end(), [&](int u, int v) {
            return cloud[u] < cloud[v];
        });

        for (int i = k = 0; i < n; ch[k++] = o[i++])
            while (k > 1 && sign(cross(cloud[ch[k - 1]] - cloud[ch[k - 2]], cloud[o[i]] - cloud[ch[k - 2]])) >= int(allow_collinear))
                --k;

        for (int i = n - 2, t = k; i >= 0; ch[k++] = o[i--])
            while (k > t && sign(cross(cloud[ch[k - 1]] - cloud[ch[k - 2]], cloud[o[i]] - cloud[ch[k - 2]])) >= int(allow_collinear))
                --k;

        ch.resize(k - (k > 1));

        if (ccw)
        {
            std::reverse(ch.begin() + 1, ch.end());
        }

        return ch;
    }
} 

#include <random>

#define endl '\n'

using namespace asl;
using namespace std;

int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    cout.precision(1);
    cout << fixed;

    int n;
    cin >> n;

    polygon<int> pol(n);
    cin >> pol;

    auto args = arg_convex_hull(pol, true, true);
    polygon<int> from_arg;
    for (auto x : args)
    {
        from_arg.push_back(pol[x]);
    }
    pol = convex_hull(pol, true, true);

    assert(pol == from_arg);

    auto pos = min_element(pol.begin(), pol.end(), [&](point<int> a, point<int> b) {
        return a.transpose() < b.transpose();
    });

    rotate(pol.begin(), pos, pol.end());

    cout << pol.size() << endl;

    for (auto p : pol)
        cout << p << endl;

    return 0;
}





Measured memory_bytes: 6532