#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define INF 0x7fffffff
#define EPS (1e-10)
#define equals(a, b) (fabs(a-b)<EPS)
static const int CCW=1;//?????¶???
static const int CW=-1;//?????¶???
static const int BACK=2;//?????¢
static const int FRONT=-2;//?????¢
static const int ON=0;//?????????

struct Point//???
{
    double x, y;
    Point(double x=0, double y=0):x(x), y(y){}
};
typedef Point Vector;//??????

struct Segment{ Point p1, p2; };//??????
typedef Segment Line;//??´???

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

typedef vector<Point> Polygon;//????????¢

Point operator + (Point a, Point b){ return Point(a.x+b.x, a.y+b.y); }
Point operator - (Point a, Point b){ return Point(a.x-b.x, a.y-b.y); }
Point operator * (Point a, double p){ return  Point(a.x*p, a.y*p); }
Point operator / (Point a, double p){ return Point(a.x/p, a.y/p); }
bool operator < (const Point &a,const Point &b){ return a.x<b.x||(a.x==b.x&&a.y<b.y); }

double norm(Vector a){ return a.x*a.x+a.y*a.y; }//?????°????¨?????????????
double abs(Vector a){ return sqrt(norm(a)); }//?¨?
double dot(Vector a, Vector b){ return a.x*b.x+a.y*b.y; }//??????
double cross(Vector a, Vector b){ return a.x*b.y-a.y*b.x; }//??????

bool isOrthgonal(Vector a, Vector b){ return equals(dot(a, b), 0.0); }//???????????´????????????
bool isOrthgonal(Point a1, Point a2, Point b1, Point b2){ return isOrthgonal(a1-a2, b1-b2); }//???????????´???4?????????
bool isOrthgonal(Segment s1, Segment s2){ return equals(dot(s1.p2-s1.p1, s2.p2-s2.p1), 0.0); }//???????????´????????????

bool isParallel(Vector a, Vector b){ return equals(cross(a, b), 0.0); }//????????????????????????
bool isParallel(Point a1, Point a2, Point b1, Point b2){ return isParallel(a1-a2, b1-b2); }//???????????????4?????????
bool isParallel(Segment s1, Segment s2){ return equals(cross(s1.p2-s1.p1, s2.p2-s2.p1), 0.0); }//????????????????????????

Point project(Segment s, Point p)//?±?????¶?
{
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1, base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s, Point p)//?±??????°??´??????????§°???
{
    return p+(project(s, p)-p)*2.0;
}

int ccw(Point p0, Point p1, Point p2)//??????P0,P1,P2??????????????????
{
    Vector a=p1-p0;
    Vector b=p2-p0;
    if( cross(a, b)>EPS ) return CCW;
    if( cross(a, b)<-EPS ) return CW;
    if( dot(a, b)<-EPS ) return BACK;
    if( norm(a)<norm(b) ) return FRONT;
    return ON;
}

bool intersect(Point p1, Point p2, Point p3, Point p4){ return (ccw(p1, p2, p3)*ccw(p1, p2, p4)<=0 &&ccw(p3, p4, p1)*ccw(p3, p4, p2)<=0); }//???????????????4?????????
bool intersect(Segment s1, Segment s2){ return intersect(s1.p1, s1.p2, s2.p1, s2.p2); }//???????????????????????????

double getDistance(Point a, Point b){ return abs(a-b); }//????????´?????????
double getDistanceLP(Line l, Point p){ return abs(cross(l.p2-l.p1, p-l.p1)/abs(l.p2-l.p1)); }//?????°??´????????????
double getDistanceSP(Segment s, Point p)//?????°???????????????
{
    if(dot(s.p2-s.p1, p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2, p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s, p);
}
double getDistanceSS(Segment s1, Segment s2)//???????????´?????????
{
    if(intersect(s1, s2)) return 0.0;
    return min( min(getDistanceSP(s1,s2.p1), getDistanceSP(s1,s2.p2)),
                min(getDistanceSP(s2,s1.p1), getDistanceSP(s2,s1.p2)) );
}

Point getCrossPoint(Segment s1, Segment s2)//??????????????????
{
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base, s1.p1-s2.p1));
    double d2=abs(cross(base, s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}
/*
???????????¨????????¢?????¨
IN 2
ON 1
OUT 0
*/
int contains(Polygon g, Point p)
{
    int n=g.size();
    bool x=false;
    for(int i=0; i<n; i++)
    {
        Point a=g[i]-p;
        Point b=g[(i+1)%n]-p;
        if(abs(cross(a, b))<EPS && dot(a, b)<EPS) return 1;
        if(a.y>b.y) swap(a,b);
        if(a.y<EPS && EPS<b.y && cross(a,b)>EPS) x=!x;
    }
    return (x? 2 : 0);
}

Polygon andrewScan(Polygon s)
{
    Polygon u, l;
    if(s.size()<3) return s;
    sort(s.begin(), s.end());
    u.push_back(s[0]);
    u.push_back(s[1]);
    l.push_back(s[s.size()-1]);
    l.push_back(s[s.size()-2]);
    for(int i=2; i<s.size(); i++)
    {
        for(int n=u.size(); n>=2 && ccw(u[n-2], u[n-1], s[i])==CCW; n--)
            u.pop_back();
        u.push_back(s[i]);
    }
    for(int i=s.size()-3; i>=0; i--)
    {
        for(int n=l.size(); n>=2 && ccw(l[n-2], l[n-1], s[i])==CCW; n--)
            l.pop_back();
        l.push_back(s[i]);
    }
    reverse(l.begin(), l.end());
    for(int i=u.size()-2; i>=1; i--) l.push_back(u[i]);
    return l;
}

int main()
{
    int n;
    Polygon s, k;
    scanf("%d", &n);
    while(n--)
    {
        Point p;
        scanf("%lf%lf", &p.x, &p.y);
        s.push_back(p);
    }
    k=andrewScan(s);
    printf("%d\n", k.size());
    int minn=INF, o;
    for(int i=0; i<k.size(); i++)
    {
        if(k[i].y<minn)
        {
            minn=k[i].y;
            o=i;
        }
    }
    int cnt=k.size(), i=o;
    while(cnt--)
    {
        if(i>=k.size()) i-=k.size();
        printf("%.0lf %.0lf\n", k[i].x, k[i].y);
        i++;
    }
    return 0;
}

Measured memory_bytes: 10012