def cross(c1, c2):

    return c1.real * c2.imag - c1.imag * c2.real



def ccw(p0, p1, p2):

    if cross(p1 - p0, p2 - p0) > 0:

        return True

    else:

        False



# Andrew's algorithm

import collections



def andrew(point_list):

    point_list.sort(key = lambda c: (c.imag, c.real))

    point_que = collections.deque(point_list)

    convex_hull = []

    rest_points = []

    start_point = point_que.popleft()



    # outward

    convex_hull.append(start_point)

    convex_hull.append(point_que.popleft())



    while point_que:

        new_point = point_que.popleft()

        while ccw(convex_hull[-1], convex_hull[-2], new_point):

            rest_points.append(convex_hull.pop())

            if len(convex_hull) == 1:

                break

        convex_hull.append(new_point)



    # homeward

    rest_points.append(start_point)

    rest_points.sort(key = lambda c: c.imag)



    while rest_points:

        new_point = rest_points.pop()

        while ccw(convex_hull[-1], convex_hull[-2], new_point):

            convex_hull.pop()

        convex_hull.append(new_point)



    # output

    convex_hull.pop()

    print((len(convex_hull)))

    print(('\n'.join(["{0:.0f} {1:.0f}".format(p.real, p.imag) for p in convex_hull])))



# Acceptance of input

def string_to_complex(s):

    x, y = list(map(int, s.split()))

    return x + y * 1j



import sys



file_input = sys.stdin



n = int(file_input.readline())



P = [string_to_complex(file_input.readline()) for i in range(n)]



# solve

andrew(P)
def ccw(p1, p2, p3):

    return (p2[1] - p1[1]) * (p3[0] - p1[0]) - (p2[0] - p1[0]) * (p3[1] - p1[1]) > 0



# Andrew's algorithm



def andrew(point_list):

    u = []

    l = []

    point_list.sort()



    u.append(point_list[0])

    u.append(point_list[1])

    

    l.append(point_list[-1])

    l.append(point_list[-2])



    # outward

    for p in point_list[2:]:

        while ccw(u[-1], u[-2], p):

            u.pop()

            if len(u) == 1:

                break

        u.append(p)



    # homeward

    for p in point_list[-3::-1]:

        while ccw(l[-1], l[-2], p):

            l.pop()

            if len(l) == 1:

                break

        l.append(p)



    # concatenate

    u.pop()

    l.pop()

    convex_hull = u + l



    # output

    print((len(convex_hull)))

    for p in convex_hull:

        y, x = p

        print((x, y))



import sys



file_input = sys.stdin



n = int(file_input.readline())



P = []

for l in file_input:

    x, y = list(map(int, l.split()))

    P.append((y, x))



# solve

andrew(P)

def cross(c1, c2):
    return c1.real * c2.imag - c1.imag * c2.real


def ccw(p0, p1, p2):
    if cross(p1 - p0, p2 - p0) > 0:
        return True
    else:
        False


# Andrew's algorithm
import collections


def andrew(point_list):
    point_list.sort(key=lambda c: (c.imag, c.real))
    point_que = collections.deque(point_list)
    convex_hull = []
    rest_points = []
    start_point = point_que.popleft()
    # outward
    convex_hull.append(start_point)
    convex_hull.append(point_que.popleft())
    while point_que:
        new_point = point_que.popleft()
        while ccw(convex_hull[-1], convex_hull[-2], new_point):
            rest_points.append(convex_hull.pop())
            if len(convex_hull) == 1:
                break
        convex_hull.append(new_point)
    # homeward
    rest_points.append(start_point)
    rest_points.sort(key=lambda c: c.imag)
    while rest_points:
        new_point = rest_points.pop()
        while ccw(convex_hull[-1], convex_hull[-2], new_point):
            convex_hull.pop()
        convex_hull.append(new_point)
    # output
    convex_hull.pop()
    print((len(convex_hull)))
    print(("\n".join(["{0:.0f} {1:.0f}".format(p.real, p.imag) for p in convex_hull])))


# Acceptance of input
def string_to_complex(s):
    x, y = list(map(int, s.split()))
    return x + y * 1j


import sys

file_input = sys.stdin
n = int(file_input.readline())
P = [string_to_complex(file_input.readline()) for i in range(n)]
# solve
andrew(P)

def ccw(p1, p2, p3):
    return (p2[1] - p1[1]) * (p3[0] - p1[0]) - (p2[0] - p1[0]) * (p3[1] - p1[1]) > 0


# Andrew's algorithm
def andrew(point_list):
    u = []
    l = []
    point_list.sort()
    u.append(point_list[0])
    u.append(point_list[1])
    l.append(point_list[-1])
    l.append(point_list[-2])
    # outward
    for p in point_list[2:]:
        while ccw(u[-1], u[-2], p):
            u.pop()
            if len(u) == 1:
                break
        u.append(p)
    # homeward
    for p in point_list[-3::-1]:
        while ccw(l[-1], l[-2], p):
            l.pop()
            if len(l) == 1:
                break
        l.append(p)
    # concatenate
    u.pop()
    l.pop()
    convex_hull = u + l
    # output
    print((len(convex_hull)))
    for p in convex_hull:
        y, x = p
        print((x, y))


import sys

file_input = sys.stdin
n = int(file_input.readline())
P = []
for l in file_input:
    x, y = list(map(int, l.split()))
    P.append((y, x))
# solve
andrew(P)

-def cross(c1, c2): -    return c1.real * c2.imag - c1.imag * c2.real - - -def ccw(p0, p1, p2): -    if cross(p1 - p0, p2 - p0) > 0: -        return True -    else: -        False +def ccw(p1, p2, p3): +    return (p2[1] - p1[1]) * (p3[0] - p1[0]) - (p2[0] - p1[0]) * (p3[1] - p1[1]) > 0 -import collections - - -    point_list.sort(key=lambda c: (c.imag, c.real)) -    point_que = collections.deque(point_list) -    convex_hull = [] -    rest_points = [] -    start_point = point_que.popleft() +    u = [] +    l = [] +    point_list.sort() +    u.append(point_list[0]) +    u.append(point_list[1]) +    l.append(point_list[-1]) +    l.append(point_list[-2]) -    convex_hull.append(start_point) -    convex_hull.append(point_que.popleft()) -    while point_que: -        new_point = point_que.popleft() -        while ccw(convex_hull[-1], convex_hull[-2], new_point): -            rest_points.append(convex_hull.pop()) -            if len(convex_hull) == 1: +    for p in point_list[2:]: +        while ccw(u[-1], u[-2], p): +            u.pop() +            if len(u) == 1: -        convex_hull.append(new_point) +        u.append(p) -    rest_points.append(start_point) -    rest_points.sort(key=lambda c: c.imag) -    while rest_points: -        new_point = rest_points.pop() -        while ccw(convex_hull[-1], convex_hull[-2], new_point): -            convex_hull.pop() -        convex_hull.append(new_point) +    for p in point_list[-3::-1]: +        while ccw(l[-1], l[-2], p): +            l.pop() +            if len(l) == 1: +                break +        l.append(p) +    # concatenate +    u.pop() +    l.pop() +    convex_hull = u + l -    convex_hull.pop() -    print(("\n".join(["{0:.0f} {1:.0f}".format(p.real, p.imag) for p in convex_hull]))) - - -# Acceptance of input -def string_to_complex(s): -    x, y = list(map(int, s.split())) -    return x + y * 1j +    for p in convex_hull: +        y, x = p +        print((x, y)) -P = [string_to_complex(file_input.readline()) for i in range(n)] +P = [] +for l in file_input: +    x, y = list(map(int, l.split())) +    P.append((y, x))