#include <iostream>
#include <math.h>
#include <cmath>
#include <iomanip>
#include <stack>
#include <queue>


using namespace std;

//-------------------------------------------------------------------------------------
/*2点[(x1,y1),(x2,y2)]を入力し二点を通る直線ax+by+cの(a,b,c)を返す,  */
/*x1==x2ならfalseを返す*/
/*falseならばx=cの形の直線*/
void straight_line_passing_through_the_two_points(double x1, double y1, double x2, double y2, double *a, double *b, double *c){
    *a=(y2-y1);
    *b=-(x2-x1);
    *c=y2*(x2-x1)-x2*(y2-y1);
}

//-------------------------------------------------------------------------------------
/*(x,y)を通るa1x+b1y+c1=0に垂直な直線a2x+b2y+c2=0を返す*/
bool vertical_straight_line(double x, double y, double a1, double b1, double c1, double *a2, double *b2, double *c2){
    if(a1*x+b1*y+c1==0)return false;
    *a2 = -b1;
    *b2 = a1;
    *c2 = b1*x - a1*y;
    return true;
}


//-------------------------------------------------------------------------------------
/*2直線 a1x+b1y+c1=0 a2x+b2y+c2=0 の交点 (x,y)を返す*/
/*2直線が平行であるならば0を返す*/
int intersection_and_parallel(double a1, double b1, double c1, double a2, double b2, double c2, double *x, double *y){
    if(a1*b2==a2*b1)return false;//平行の判定
    
    *x = (b1*c2-b2*c1)/(a1*b2-a2*b1);
    *y = (a2*c1-a1*c2)/(a1*b2-a2*b1);
    
    return true;
}

//-------------------------------------------------------------------------------------
/* 
 a1x+b1y+c1=0 と　a2x+b2y+c2=0 が
 平行なら2
 直交なら1
 それ以外は0
 を返す
 */
int judges_whether_parallel_or_perpendicular(double a1, double b1, double c1, double a2, double b2, double c2){
    if(a1*b2 == a2*b1)return 2;
    if(a1*a2 + b1*b2 == 0)return 1;
    return 0;
}


//-------------------------------------------------------------------------------------
/*直線ax+by+c=0に対し　(x1,y1)と線対称な位置(x2,y2)を出力*/
/*vertical_straight_lineを使用*/
/*intersection_and_parallelを使用*/
void line_symmetry(double a, double b, double c, double x1, double y1, double *x2, double *y2){
    //垂直な直線を求める
    double a2,b2,c2;
    vertical_straight_line(x1, y1, a, b, c, &a2, &b2, &c2);
    
    //垂直な直線との交点を求める
    double c_x, c_y;
    intersection_and_parallel(a, b, c, a2, b2, c2, &c_x, &c_y);
    *x2 = x1 + 2*(c_x-x1);
    *y2 = y1 + 2*(c_y-y1);
}



//-------------------------------------------------------------------------------------
/*2点(x1,y1), (x2,y2) の距離*/
double distance_between_the_two_pointss(double x1,double y1, double x2, double y2){
    return  sqrt(fabs((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
}


//-------------------------------------------------------------------------------------
/* (x1,y1)から(x2,y2)へ伸ばした直線の角度を求める  */
/*-π　〜　+π　まで*/
double angle_of_the_line(double x1, double y1, double x2, double y2){
    return atan2(y2-y1, x2-x1);
}

//-------------------------------------------------------------------------------------
/*(x1,y1)と(x2,y2)を両端に持つ線分と*/
/*(x3,y3)と(x4,y4)を両端に持つ線分が*/
/*交差するなら1 交差しないなら0を出力する*/
/* straight_line_passing_through_the_two_pointsを使用 */
/* intersection_and_parallelを使用 */
int line_segment_cross_decision(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4){
    double a1,b1,c1, a2,b2,c2;
    straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a1, &b1, &c1);
    straight_line_passing_through_the_two_points(x3, y3, x4, y4, &a2, &b2, &c2);
    double c_x,c_y;
    bool is_parallel = intersection_and_parallel(a1, b1, c1, a2, b2, c2, &c_x, &c_y);
    if(is_parallel==false){
        if( (a1==a2&&b1==b2&&c1==c2) || (a1==0 && (b1/b2)==(c1/c2)) || (b1==0 && (a1/a2)==(c1/c2)) ){//一直線上にある.
            //cout<<1111;
            if(min(x1,x2)<=x3&&x3<=max(x1,x2)&&min(y1,y2)<=y3&&y3<=max(y1,y2))return 1;
            if(min(x1,x2)<=x4&&x4<=max(x1,x2)&&min(y1,y2)<=y4&&y4<=max(y1,y2))return 1;
            if(min(x3,x4)<=x1&&x1<=max(x3,x4)&&min(y3,y4)<=y1&&y1<=max(y3,y4))return 1;
            if(min(x3,x4)<=x2&&x2<=max(x3,x4)&&min(y3,y4)<=y2&&y2<=max(y3,y4))return 1;
            


        }
        return 0;
    }
    if(x1>x2)swap(x1, x2);
    if(x3>x4)swap(x3, x4);
    if(y1>y2)swap(y1, y2);
    if(y3>y4)swap(y3, y4);

    if(x1<=c_x&&c_x<=x2&&x3<=c_x&&c_x<=x4){
        if(y1<=c_y&&c_y<=y2&&y3<=c_y&&c_y<=y4)return 1;
    }
    return 0;
    
}



//-------------------------------------------------------------------------------------
/*点(p_x,p_y)と線分(x1,y1)(x2,y2)の距離*/
/* straight_line_passing_through_the_two_points */
/* vertical_straight_line */
/* intersection_and_parallel */
double distance_between_the_line_segment_and_point(double p_x, double p_y, double x1, double y1, double x2, double y2){
    double a,b,c;//(x1,y1)(x2,y2)を通る直線
    straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a, &b, &c);
    double a2,b2,c2;//直線ax+by+c=0に垂直な直線
    double v_x, v_y;//二つの直線の交点
    bool is_not_parallel = vertical_straight_line(p_x, p_y, a, b, c, &a2, &b2, &c2);
    intersection_and_parallel(a, b, c, a2, b2, c2, &v_x, &v_y);
    
    if(is_not_parallel){
        if(min(x1,x2)<=v_x&&v_x<=max(x1,x2)&&min(y1,y2)<=v_y&&v_y<=max(y1,y2)){//(v_x,v_y)は線分の中にある
            //cout<<"a ";
            return distance_between_the_two_pointss(p_x, p_y, v_x, v_y);
        }else{//(v_x,v_y)は線分の外にある
            double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
            double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
            //cout<<"b ";
            return min(l1,l2);
        }
    }else{
        if(min(x1,x2)<=p_x&&p_x<=max(x1,x2)&&min(y1,y2)<=p_y&&p_y<=max(y1,y2)){//(p_x,p_y)は線分の中にある
            //cout<<"c ";
            return 0.0;
        }else{//(p_x,p_y)は線分の外にある
            double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
            double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
            //cout<<"d ";
            return min(l1,l2);
        }
    }
    
}


//-------------------------------------------------------------------------------------
/*線分(x1,y1)(x2,y2)と線分(x3,y3)(x4,y4)の距離*/

double distance_between_two_line_segment(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4){
    //同一直線上にある場合
    
    //ぶつかる場合
    if(line_segment_cross_decision(x1, y1, x2, y2, x3, y3, x4, y4)){
        return 0.0;
    }
    
    //ぶつからない場合
    double l1,l2,l3,l4;
    l1=distance_between_the_line_segment_and_point(x1, y1, x3, y3, x4, y4);
    //cout<<l1<<endl;
    l2=distance_between_the_line_segment_and_point(x2, y2, x3, y3, x4, y4);
    //cout<<l2<<endl;

    l3=distance_between_the_line_segment_and_point(x3, y3, x1, y1, x2, y2);
    //cout<<l3<<endl;
    l4=distance_between_the_line_segment_and_point(x4, y4, x1, y1, x2, y2);
    
        
    //cout<<l4<<endl;
    
    return min(l1,min(l2,min(l3,l4)));
}

//-------------------------------------------------------------------------------------
/*多角形の面積*/
/*頂点数n　頂点の集合 */
double area_of_the_polygon(int n, double p_xy[10000][2]){
    double s=0.0;
    for(int i=0; i<n; i++){
        s+=(p_xy[i][0]-p_xy[(i+1)%n][0])*(p_xy[i][1]+p_xy[(i+1)%n][1])/2;
    }
    return s;
}


//-------------------------------------------------------------------------------------
/*角abcの角度　a(xa,ya), b(xb,yb), c(xc,yc),*/
/*2辺の角度*/
/*aとb　またはbとcが重なっていればPIを返す*/
double angle_of_the_two_edges(double ax, double ay, double bx, double by, double cx, double cy){
    if(ax==bx&&ay==by)return M_PI;
    if(cx==bx&&cy==by)return M_PI;
    
    double angle1 = angle_of_the_line(ax, ay, bx, by);
    double angle2 = angle_of_the_line(bx, by, cx, cy);
    
    double ret = angle1+(M_PI-angle2);
    if(ret>M_PI * 2)ret -= M_PI * 2;
    if(ret<0)ret += M_PI * 2;
    return ret;
    
}

//-------------------------------------------------------------------------------------
/*多角形に対する点の内外判定*/
/* n頂点の多角形p_xy[n]に対して点(x,y)の内外判定を行う*/
/* 内なら2 線上なら1 外なら0*/
int inside_and_outside_the_determination_of_the_polygon_and_point(int n, double p_xy[10000][2], double x, double y){
    //点が線分上にあるか
    for(int i=0; i<n; i++){
        double l = distance_between_the_line_segment_and_point(x, y, p_xy[i][0], p_xy[i][1], p_xy[(i+1)%n][0], p_xy[(i+1)%n][1]);
        if(l==0.0)return 1;
    }
    
    //点が中にあるか外にあるか
    int ans = 0;
    for(int i=0; i<n; i++){
        if(p_xy[i][0]!=p_xy[(i+1)%n][0]){
            ans += line_segment_cross_decision(p_xy[i][0], p_xy[i][1], p_xy[(i+1)%n][0], p_xy[(i+1)%n][1], x, y, x, y+1000000.0);
            
            if(distance_between_the_line_segment_and_point(p_xy[i][0], p_xy[i][1],x, y, x, y+1000000.0)==0.0){
                if(p_xy[i][0]>p_xy[(i+1)%n][0])ans--;
            }
            if(distance_between_the_line_segment_and_point(p_xy[(i+1)%n][0], p_xy[(i+1)%n][1],x, y, x, y+1000000.0)==0.0){
                if(p_xy[i][0]<p_xy[(i+1)%n][0])ans--;
            }
        }
        
    }
    //cout<<" "<<ans<<" ";
    if(ans%2==0)return 0;
    else return 2;
}
//-------------------------------------------------------------------------------------
/*二点の角度*/
/*0~2π*/
double angle_line_0_359(double x1, double y1, double x2, double y2){
    double angle = atan2(y2-y1, x2-x1);
    if(angle<0)angle = 2*M_PI+angle;
    return angle;
}

//-------------------------------------------------------------------------------------
/*二辺の角度*/
/*反時計回りの内側*/
/*0~2π*/
double angle_two_line_0_359(double x1, double y1, double x2, double y2, double x3, double y3){
    double angle = atan2(y2-y1, x2-x1);
    if(angle<0)angle = 2*M_PI+angle;
    if(angle==2*M_PI)angle=0.0;
    
    double angle2 = atan2(y3-y2, x3-x2);
    if(angle2<0)angle2 = 2*M_PI+angle2;
    if(angle2==2*M_PI)angle2=0.0;
    
    return angle+(M_PI-angle2);
}

//-------------------------------------------------------------------------------------
/*二次元配列のクイックソート*/
/*xoryが0ならx座標　1なら座標でソート*/
void two_dimensional_qsort(double xy[100000][2], int left, int right, int xory)
{
    int i, j;
    double pivot,pivot2;
    
    i = left;                      /* ソートする配列の一番小さい要素の添字 */
    j = right;                     /* ソートする配列の一番大きい要素の添字 */
    
    pivot = xy[(left + right) / 2][xory]; /* 基準値を配列の中央付近にとる */
    pivot2 = xy[(left + right) / 2][(xory+1)%2];
    
    
    while (1) {                    /* 無限ループ */
        
        while (xy[i][xory] < pivot || (xy[i][xory] == pivot && xy[i][(xory+1)%2] < pivot2))       /* pivot より大きい値が */
            i++;                   /* 出るまで i を増加させる */
        
        while (pivot < xy[j][xory] || (xy[j][xory] == pivot &&  pivot2 < xy[j][(xory+1)%2]))       /* pivot より小さい値が */
            j--;                   /*  出るまで j を減少させる */
        if (i >= j)                /* i >= j なら */
            break;                 /* 無限ループから抜ける */
        
        swap(xy[i][xory], xy[j][xory]);            /* x[i] と x[j]を交換 */
        swap(xy[i][(xory+1)%2], xy[j][(xory+1)%2]);            /* x[i] と x[j]を交換 */
        i++;                       /* 次のデータ */
        j--;
    }
    
    if (left < i - 1)              /* 基準値の左に 2 以上要素があれば */
        two_dimensional_qsort(xy, left, i - 1, xory);     /* 左の配列を Q ソートする */
    if (j + 1 <  right)            /* 基準値の右に 2 以上要素があれば */
        two_dimensional_qsort(xy, j + 1, right, xory);    /* 右の配列を Q ソートする */
}

//-------------------------------------------------------------------------------------
/*凸包*/
/*２次元平面における点の集合Pに対する凸包（convex hull）を求めて下さい。凸包とは点集合Pの全ての点を含む最小の凸多角形です。*/
/*集合の要素数 n*/
/*集合 p_xy[1000000][2]*/
/*解答の要素数 q*/
/*解答 ans[1000000][2]　最も下の最も左から反時計回り*/

void convex_hull(int n, double p_xy[100000][2], int *q, double ans[100000][2]){

    two_dimensional_qsort(p_xy, 0, n-1, 1);
    /*
    for(int i=0; i<n; i++){
        cout<<p_xy[i][0]<<" "<<p_xy[i][1]<<endl;
    }
     */
    
    
    int k=0;
    for(int i=0; i<n; i++){
        while(k > 1 && (angle_two_line_0_359(ans[k-2][0], ans[k-2][1], ans[k-1][0], ans[k-1][1], p_xy[i][0], p_xy[i][1])>M_PI))k--;
        ans[k][0]=p_xy[i][0];
        ans[k][1]=p_xy[i][1];
        k++;
    }
    
    
    int t=k;
    for(int i=n-2; i>=0; i--){
        while(k > t && (angle_two_line_0_359(ans[k-2][0], ans[k-2][1], ans[k-1][0], ans[k-1][1], p_xy[i][0], p_xy[i][1])>M_PI))k--;
        ans[k][0]=p_xy[i][0];
        ans[k][1]=p_xy[i][1];
        k++;
    }
     
     
    
    
    
    
    *q=k-1;
    
}
int main(int argc, const char * argv[]){
    //cout<<angle_two_line_0_359(0,0, 2,1,4,2)/M_PI<<endl;

    //cout<<angle_of_the_line(0,0,0,0)/M_PI * 180<<endl;
    //cout<<angle_line_0_359(1, 3,2, 2)/M_PI*180.0<<endl;
    //cout<<angle_line_0_359(1, 3,0, 0)/M_PI*180.0<<endl;

    
    int n;
    while(cin>>n){
        double p_xy[100000][2]={0};
        for(int i=0; i<n; i++){
            cin>>p_xy[i][0]>>p_xy[i][1];
        }
        
        two_dimensional_qsort(p_xy, 0, n-1, 1);
        /*
        for(int i=0; i<n; i++){
            cout<<p_xy[i][0]<<" "<<p_xy[i][1]<<endl;
        }
        */
        int q;
        double ans[100000][2]={0};
        convex_hull(n, p_xy, &q, ans);
        cout<<q<<endl;
        for(int i=0; i<q; i++){
            cout<<ans[i][0]<<" "<<ans[i][1]<<endl;
        }
    }
}

Measured memory_bytes: 4876