#include <iostream>
#define max(x0, x1, base) (x0.x-base.x!=0)?((x0.y-base.y)/(x0.x-base.x)>(x1.y-base.y)/(x1.x-base.x)?0:1):((x0.y-base.y)>(x1.y-base.y)?0:1)
#define cross_product(A, B, C) (B.x-A.x)*(C.y-A.y)-(B.y-A.y)*(C.x-A.x)
using namespace std;
struct point
{
double x, y;
};
point points[120001], stack[120001];
void fix_heap(point basis, point point_array[], long root, point key, long bound)
{
long vacant = root;
while (2*vacant <= bound)
{
long larger_child=2*vacant;
if (larger_child < bound && max(point_array[larger_child], point_array[larger_child+1], basis))
larger_child++;
if (max(point_array[larger_child], key, basis))
break;
else
point_array[vacant]=point_array[larger_child];
vacant = larger_child;
}
point_array[vacant] = key;
}
void angle_sort(point basis, long n, point point_array[])
{
point max;
for(long i=n/2; i>0; --i)
fix_heap(basis, point_array, i, point_array[i], n);
for(long i=n; i>1; --i)
{
max = point_array[1];
fix_heap(basis, point_array, 1, point_array[i], i-1);
point_array[i]=max;
}
point_array[0]=point_array[n];
}
void read (long &n, point v[])
{
freopen("infasuratoare.in", "r", stdin);
scanf("%ld", &n);
for (int i=1; i<=n; ++i)
{
scanf("%lf%lf", &v[i].x, &v[i].y);
if(v[i].x<v[0].x || (v[i].x==v[0].x && v[i].y<v[0].y))
v[0]=v[i];
}
}
void write (long n, point v[])
{
freopen("infasuratoare.out", "w", stdout);
printf("%ld\n", n);
for (int i=0; i<n; ++i)
printf("%lf %lf\n", (v+i)->x, (v+i)->y);
}
long convex_hull(long n, point points[], point hull[])
{
int stack_index=0;
hull[stack_index++]=points[0];
hull[stack_index++]=points[1];
for(long i=2; i<n; )
{
hull[stack_index++]=points[i++];
while(cross_product(hull[stack_index-3], hull[stack_index-2], hull[stack_index-1])<0)
{
hull[stack_index-2]=hull[stack_index-1];
stack_index--;
}
}
return stack_index;
}
int main()
{
long n, hn;
read(n, points);
angle_sort(points[0], n, points);
hn=convex_hull(n, points, stack);
write(n, points);
write(hn, stack);
return 0;
}