/*
主要的问题就是极角排序不一定
是逆时针，就最后一条边的回到起点的时候
有多个点，就会顺序错误

还有个问题就是不能在polygon里面开太大的point数组
这时就要用vector处理，所以这是改bin巨板子基础上的vector表示
*/
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
typedef long long ll;
int sgn(double x){
    if(fabs(x)<eps){
        return 0;
    }
    if(x<0){
        return -1;
    }else{
        return 1;
    }
}

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x = _x;
        y = _y;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
        // return sgn(y-b.y)==0?x<b.x:y<b.y;
    }
    bool operator == (Point b)const{
        return sgn(x-b.x)==0&&sgn(y-b.y)==0;
    }
    Point operator -(const Point &b)const{
        return Point(x-b.x,y-b.y);
    }
    double operator ^(const Point &b)const{
        return x*b.y-y*b.x;
    }
    Point operator /(const double& k)const{
        return Point(x/k,y/k);
    }
    double distance(Point p){
        return hypot(x-p.x,y-p.y);
    }
};
struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e){
        s  = _s;
        e = _e;
    }
};
struct polygon{
    int n;
    vector<Point> p;
    // Line l[maxp];
    void input(int _n){
        n = _n;
        Point tt;
        for(int i = 0;i < n;++i ){
            tt.input();
            p.push_back(tt);
        }
    }
    struct cmp{    //排序规则：
        Point p;
        cmp(const Point &p0){
            p = p0;
        }
        bool operator ()(const Point &aa,const Point &bb){
            Point a = aa,b = bb;
            int d = sgn((a-p)^(b-p));
            if(d == 0){
                return sgn(a.distance(p)-b.distance(p))<0;
            }
            return d>0;
        }
    };
    void norm(){
        Point mi = p[0];
        for(int i = 1;i < n;++i ){
            mi = min(mi,p[i]);
        }
        sort(p.begin(),p.end(),cmp(mi));
    }
    // 安德鲁算法
     void getconvex(polygon &convex){
        sort(p.begin(),p.end());
        convex.n = n;
        for(int i = 0;i < min(n,2);++i ){
            convex.p.push_back(p[i]);
        }
        if(convex.n == 2&&(convex.p[0] == convex.p[1])){
            convex.n--;   //特判
        }
        if(n<=2){
            return;
        }
        for(int i = 2;i < n;++i ){
            while(convex.p.size()>1 && sgn((convex.p[convex.p.size()-1]-p[i])^(convex.p[convex.p.size()-2]-p[i]))<0){
                convex.p.pop_back();
            }
            convex.p.push_back(p[i]);
        }
        int temp = convex.p.size()-1;
        convex.p.push_back(p[n-2]);
        for(int i = n-3;i >= 0;i--){
            while(convex.p.size()-1 != temp && sgn((convex.p[convex.p.size()-1]-p[i])^(convex.p[convex.p.size()-2]-p[i]))<0){
                convex.p.pop_back();
            }
            convex.p.push_back(p[i]);
        }
        convex.n = convex.p.size();
        if(convex.n == 2 && (convex.p[0] == convex.p[1])){
            convex.n--;
        }
       reverse(convex.p.begin(),convex.p.end());
       convex.p.pop_back();
    }
};

int main(){
    int n;
    scanf("%d",&n);
    polygon pp;
    pp.input(n);
    polygon ans;
    pp.getconvex(ans);
    int tmp = ans.p.size();
    printf("%d\n",tmp);
    int ii;
    double minn = inf;
    for(int i = 0;i < tmp;++i ){
        if(sgn(ans.p[i].y-minn)<0){
            minn = ans.p[i].y;
            ii = i;
        }else if(sgn(ans.p[i].y-minn)==0 && sgn(ans.p[i].x-ans.p[ii].x)<0){
            minn = ans.p[i].y;
            ii = i;
        }
    }
    for(int i = 0;i < tmp;++i ){
        printf("%d %d\n",(int)(ans.p[(i+ii)%tmp].x),(int)(ans.p[(i+ii)%tmp].y));
    }
     return 0;
}


Measured memory_bytes: 7380