#include <bits/stdc++.h>

#define EPS (1e-10)
#define rep(i, a, b) for (int i = a; i < (int)(b); ++i)
#define rrep(i, a, b) for (int i = b - 1; i >= (int)(a); --i)

using namespace std;
using ll = long long;
using vi = vector<int>;
using vll = vector<ll>;
using vd = vector<double>;
using vvi = vector<vi>;

constexpr int MOD = 1000000007;

// Data structures.
struct Point {
    double x, y;
    Point(double x = 0, double y = 0) : x(x), y(y) {}
    Point(const Point& p) : x(p.x), y(p.y) {}

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

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

    static double norm(const Point& p) { return sqrt(p.x * p.x + p.y * p.y); }
    static double dot(const Point& p1, const Point& p2) { return p1.x * p2.x + p1.y * p2.y; }
    static double cross(const Point& p1, const Point& p2) { return p1.x * p2.y - p1.y * p2.x; }
};
struct Segment {
    Point s, t;
    Segment(const Point& s, const Point& t) : s(s), t(t) {}
    Segment(const Segment& seg) : s(seg.s), t(seg.t) {}
};

typedef vector<Point> Polygon;

int ccw(const Point& p0, const Point& p1, const Point& p2) {
    double cr = Point::cross(p1 - p0, p2 - p0);
    if (cr > EPS) { return 1; }
    if (cr < -EPS || fabs(cr) < EPS) { return -1; }
    if (Point::dot(p1 - p0, p2 - p0) < -EPS) { return 2; }
    if (Point::dot(p2 - p1, p0 - p1) < -EPS) { return -2; }
    return 0;
}

Polygon andrew(Polygon poly) {
    int n = poly.size();
    if (n < 3) { return poly; }

    // Sort.
    sort(poly.begin(), poly.end(),
         [](const Point& p1, const Point& p2) -> bool { return p1.y != p2.y ? p1.y < p2.y : p1.x < p2.x; });

    // Upper part.
    Polygon U = {poly[0], poly[1]};
    rep(i, 2, n) {
        int j = U.size();
        while (j >= 2 && ccw(U[j - 2], U[j - 1], poly[i]) != -1) {
            U.pop_back();
            --j;
        }
        U.push_back(poly[i]);
    }

    // Lower part.
    Polygon L = {poly[n - 1], poly[n - 2]};
    rrep(i, 0, n - 2) {
        int j = L.size();
        while (j >= 2 && ccw(L[j - 2], L[j - 1], poly[i]) != -1) {
            L.pop_back();
            --j;
        }
        L.push_back(poly[i]);
    }

    reverse(L.begin(), L.end());
    rrep(i, 1, U.size() - 1) { L.push_back(U[i]); }

    return L;
}

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

    int n;
    cin >> n;

    Polygon poly(n);
    rep(i, 0, n) { cin >> poly[i].x >> poly[i].y; }

    Polygon ans = andrew(poly);
    cout << ans.size() << endl;
    rep(i, 0, ans.size()) { cout << ans[i].x << " " << ans[i].y << endl; }

    return 0;
}
