/** @Cain*/
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <bitset>
#include <functional>
#include <cstdlib>
#define PI acos(-1.0)
#define ll long long int
#define db double
#define ull unsigned long long int
#define Fill(x,y) memset(x,y,sizeof(x))
#define bug printf("!!!!!!\n");
using namespace std;
const int mod = 1e9+7;
const db eps=1e-6;
const int inf=1e9;
const ll INF=1e15;
int cas=1;
const int maxn=1e5+5;
struct point
{
    int x,y;
    point(int x=0,int y=0):x(x),y(y){}
    friend int operator * (const point& a,const point& b){
        return a.x*b.y - a.y*b.x;
    }

    bool operator < (const point &a) const {  //先?x小的排前面,然后再?y小的排前面.
        if(a.x == x) return a.y>y;
        return a.x>x;
    }

}tb[maxn],po[maxn];

point xl(const point& a,const point& b)  //向量b->a
{         //???参就是快. 没有其他?子意思
    return point(a.x-b.x,a.y-b.y);
}

void solve()
{
    int n; scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&po[i].x,&po[i].y);
    }
    sort(po+1,po+n+1);
   /* for(int i=1;i<=n;i++){
        printf("%d %d\n",po[i].x,po[i].y);
    }
    bug;*/
    int m = 0; //看此?的?有多少个元素.
    for(int i=1;i<=n;i++){   //画一个?以后?会?????完一遍后,只形成了半个凸包.
        while(m>1 && xl(po[i],tb[m-2]) * xl(tb[m-1],tb[m-2]) > 0) m--;  //等于号是判共?的.
        tb[m++] = po[i]; //意思是当前?个点如果在前一个点的右?,?前一个点就不要.
    }                    //?住我?判要不要的点都是判的前一个点. 而不是当前?个点.
    int tmp = m;
    for(int i=n-1;i>=1;i--){  //所以?要反着?一遍,??一?.
        while(m>tmp && xl(po[i],tb[m-2]) * xl(tb[m-1],tb[m-2]) > 0) m--; //?道例?共?是要的.
        tb[m++] = po[i];
    }
    if(n>2) m--; // 起点被加了?次.
    printf("%d\n",m);
    for(int i=0;i<m;i++){
        printf("%d %d\n",tb[i].x,tb[i].y);
    }
}

int main()
{
    // freopen("in.txt","r",stdin);
    //  freopen("out.txt","w",stdout);
    int t = 1 ;
    //scanf("%d",&t);
    while(t--){
    //    printf("Case %d: ", cas++);
        solve();
        //printf("\n");
    }
}