#include <algorithm>
#include <cmath>
#include <cstddef>
#include <iostream>
#include <string>
#include <vector>

const double kEpsilon = 1e-10;
inline bool equals(double a, double b)
{
    return fabs(a - b) < kEpsilon;
}

class Point
{
  public:
    double x, y;

    Point() = default;
    Point(double x, double y) : x(x), y(y)
    {
    }

    Point operator+(const Point &p)
    {
        return Point(x + p.x, y + p.y);
    }
    Point operator-(const Point &p)
    {
        return Point(x - p.x, y - p.y);
    }
    Point operator*(const double k)
    {
        return Point(x * k, y * k);
    }

    double SquaredNorm()
    {
        return x * x + y * y;
    }
    double abs()
    {
        return sqrt(this->SquaredNorm());
    }

    // bool operator<(const Point &p) const
    // {
    //     return x != p.x ? x < p.x : y < p.y;
    // }
    // bool operator>(const Point &p) const
    // {
    //     return x != p.x ? x > p.x : y > p.y;
    // }
    bool operator<(const Point &p) const
    {
        return y != p.y ? y < p.y : x < p.x;
    }
    bool operator>(const Point &p) const
    {
        return y != p.y ? y > p.y : x > p.x;
    }

    bool operator==(const Point &p) const
    {
        return fabs(x - p.x) < kEpsilon && fabs(y - p.y) < kEpsilon;
    }

    double dot(const Point &p) const
    {
        return x * p.x + y * p.y;
    }
    double cross(const Point &p) const
    {
        return x * p.y - y * p.x;
    }
};

double dot(const Point &p1, const Point &p2)
{
    return p1.x * p2.x + p1.y * p2.y;
}
double cross(const Point &p1, const Point &p2)
{
    return p1.x * p2.y - p1.y * p2.x;
}

using Vector = Point;

struct Segment
{
    Point p1, p2;

    Segment() = default;
    Segment(Point p1, Point p2) : p1(p1), p2(p2)
    {
    }
};
using Line = Segment;

class Circle
{
  public:
    Point c;
    double r;
    Circle(Point c = Point(), double r = 0.0) : c(c), r(r)
    {
    }
};

using Polygon = std::vector<Point>;

std::string clockwise(Point &p0, Point &p1, Point &p2)
{

    Vector a, b;
    a = p1 - p0;
    b = p2 - p0;

    auto cross_z = a.cross(b);

    if (cross_z > 0.0)
        return "COUNTER_CLOCKWISE";
    else if (cross_z < 0.0)
        return "CLOCKWISE";
    else
    {
        auto dot_prod = a.dot(b);
        if (dot_prod < 0.0)
            return "ONLINE_BACK";
        else if (b.abs() > a.abs())
            return "ONLINE_FRONT";
        else
        {
            return "ON_SEGMENT";
        }
    }
}

void convexHullHalf(Polygon &points, Polygon &convex_hull)
{
    for (auto p : points)
    {
        if (convex_hull.size() <= 1)
        {
            convex_hull.push_back(p);
            continue;
        }

        std::string loc = "COUNTER_CLOCKWISE";
        while (loc == "COUNTER_CLOCKWISE" && convex_hull.size() >= 2)
        {
            Point p1 = *(convex_hull.end() - 1);
            Point p0 = *(convex_hull.end() - 2);

            loc = clockwise(p0, p1, p);
            if (loc == "COUNTER_CLOCKWISE")
                convex_hull.pop_back();
        }

        convex_hull.push_back(p);
    }
}

Polygon convexHull(Polygon &points)
{
    Polygon convex_upper, convex_lower;

    std::sort(points.begin(), points.end(), [](Point a, Point b) { return a < b; });
    convexHullHalf(points, convex_upper);
    std::reverse(points.begin(), points.end());
    convexHullHalf(points, convex_lower);

    std::reverse(convex_lower.begin(), convex_lower.end());
    for (size_t i = convex_upper.size() - 2; i >= 1; --i)
    {
        convex_lower.push_back(convex_upper.at(i));
    }
    return convex_lower;
}

int main()
{
    int n;
    std::cin >> n;

    std::vector<Point> points;
    Point p;
    for (size_t i = 0; i < n; ++i)
    {
        std::cin >> p.x >> p.y;
        points.push_back(p);
    }

    auto ans = convexHull(points);
    std::cout << ans.size() << std::endl;

    for (auto p : ans)
    {
        std::cout << p.x << " " << p.y << std::endl;
    }
}



Measured memory_bytes: 8120