macro_rules ! input { ( source = $ s : expr , $ ( $ r : tt ) * ) => { let mut iter = $ s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; ( iter = $ iter : ident , $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut $ iter = s . split_whitespace ( ) ; input_inner ! { $ iter , $ ( $ r ) * } } ; ( $ ( $ r : tt ) * ) => { let s = { use std :: io :: Read ; let mut s = String :: new ( ) ; std :: io :: stdin ( ) . read_to_string ( & mut s ) . unwrap ( ) ; s } ; let mut iter = s . split_whitespace ( ) ; input_inner ! { iter , $ ( $ r ) * } } ; }
macro_rules ! input_inner { ( $ iter : expr ) => { } ; ( $ iter : expr , ) => { } ; ( $ iter : expr , mut $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let mut $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , mut $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , mut $ var : usize $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident : $ t : tt $ ( $ r : tt ) * ) => { let $ var = read_value ! ( $ iter , $ t ) ; input_inner ! { $ iter $ ( $ r ) * } } ; ( $ iter : expr , $ var : ident $ ( $ r : tt ) * ) => { input_inner ! { $ iter , $ var : usize $ ( $ r ) * } } ; }
macro_rules ! read_value { ( $ iter : expr , ( $ ( $ t : tt ) ,* ) ) => { ( $ ( read_value ! ( $ iter , $ t ) ) ,* ) } ; ( $ iter : expr , [ $ t : tt ; $ len : expr ] ) => { ( 0 ..$ len ) . map ( | _ | read_value ! ( $ iter , $ t ) ) . collect ::< Vec < _ >> ( ) } ; ( $ iter : expr , { chars : $ base : expr } ) => { read_value ! ( $ iter , String ) . chars ( ) . map ( | c | ( c as u8 - $ base as u8 ) as usize ) . collect ::< Vec < usize >> ( ) } ; ( $ iter : expr , { char : $ base : expr } ) => { read_value ! ( $ iter , { chars : $ base } ) [ 0 ] } ; ( $ iter : expr , chars ) => { read_value ! ( $ iter , String ) . chars ( ) . collect ::< Vec < char >> ( ) } ; ( $ iter : expr , char ) => { read_value ! ( $ iter , chars ) [ 0 ] } ; ( $ iter : expr , usize1 ) => { read_value ! ( $ iter , usize ) - 1 } ; ( $ iter : expr , $ t : ty ) => { $ iter . next ( ) . unwrap ( ) . parse ::<$ t > ( ) . unwrap ( ) } ; }
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct Complex {
    pub x: f64,
    pub y: f64,
}
impl Complex {
    pub fn new(x: f64, y: f64) -> Complex {
        Complex { x: x, y: y }
    }
    pub fn from_radian(theta: f64) -> Complex {
        Complex::new(theta.cos(), theta.sin())
    }
    pub fn abs(self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
    pub fn dot(self, other: Complex) -> f64 {
        self.x * other.x + self.y * other.y
    }
    pub fn cross(self, other: Complex) -> f64 {
        self.x * other.y - self.y * other.x
    }
    pub fn conjugate(self) -> Complex {
        Complex {
            x: self.x,
            y: -self.y,
        }
    }
    pub fn angle(self) -> f64 {
        self.y.atan2(self.x)
    }
}
impl std::ops::Add for Complex {
    type Output = Complex;
    fn add(self, other: Complex) -> Complex {
        Complex {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}
impl std::ops::Add<f64> for Complex {
    type Output = Complex;
    fn add(self, other: f64) -> Complex {
        Complex {
            x: self.x + other,
            y: self.y + other,
        }
    }
}
impl std::ops::Sub for Complex {
    type Output = Complex;
    fn sub(self, other: Complex) -> Complex {
        Complex {
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}
impl std::ops::Sub<f64> for Complex {
    type Output = Complex;
    fn sub(self, other: f64) -> Complex {
        Complex {
            x: self.x - other,
            y: self.y - other,
        }
    }
}
impl std::ops::Mul for Complex {
    type Output = Complex;
    fn mul(self, other: Complex) -> Complex {
        Complex {
            x: self.x * other.x - self.y * other.y,
            y: self.x * other.y + self.y * other.x,
        }
    }
}
impl std::ops::Mul<f64> for Complex {
    type Output = Complex;
    fn mul(self, other: f64) -> Complex {
        Complex {
            x: self.x * other,
            y: self.y * other,
        }
    }
}
impl std::ops::Div for Complex {
    type Output = Complex;
    fn div(self, other: Complex) -> Complex {
        self * other.conjugate() / other.abs()
    }
}
impl std::ops::Div<f64> for Complex {
    type Output = Complex;
    fn div(self, other: f64) -> Complex {
        Complex {
            x: self.x / other,
            y: self.y / other,
        }
    }
}
impl std::ops::Neg for Complex {
    type Output = Complex;
    fn neg(self) -> Complex {
        Complex {
            x: -self.x,
            y: -self.y,
        }
    }
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum CCW {
    /// a--b--c
    OnlineFront = -2,
    /// a--b-vc
    Clockwise = -1,
    /// a--c--b
    OnSegment = 0,
    /// a--b-^c
    CounterClockwise = 1,
    /// c--a--b
    OnlineBack = 2,
}
fn ccw(a: Complex, b: Complex, c: Complex) -> CCW {
    let x = b - a;
    let y = c - a;
    if x.cross(y) > 0. {
        CCW::CounterClockwise
    } else if x.cross(y) < 0. {
        CCW::Clockwise
    } else if x.dot(y) < 0. {
        CCW::OnlineBack
    } else if x.abs() < y.abs() {
        CCW::OnlineFront
    } else {
        CCW::OnSegment
    }
}
#[derive(PartialEq, PartialOrd)]
pub struct TotalOrd<T>(pub T);
impl<T: PartialEq> Eq for TotalOrd<T> {}
impl<T: PartialOrd> Ord for TotalOrd<T> {
    fn cmp(&self, other: &TotalOrd<T>) -> std::cmp::Ordering {
        self.0.partial_cmp(&other.0).unwrap()
    }
}
fn convex_hull(ps: Vec<Complex>) -> Vec<Complex> {
    let mut ps = ps;
    ps.sort_by(|p1, p2| ((p1.x, p1.y).partial_cmp(&(p2.x, p2.y)).unwrap()));
    let mut qs = Vec::new();
    for &p in ps.iter().chain(ps.iter().rev().skip(1)) {
        while {
            let k = qs.len();
            k > 1 && ccw(qs[k - 2], qs[k - 1], p) == CCW::Clockwise
        } {
            qs.pop();
        }
        qs.push(p);
    }
    qs.pop();
    qs
}
fn main() {
    input! { n, ps: [(f64, f64); n] };
    let ps = ps
        .into_iter()
        .map(|(x, y)| Complex::new(x, y))
        .collect::<Vec<_>>();
    let ch = convex_hull(ps);
    let n = ch.len();
    let j = (0..n)
        .map(|i| (TotalOrd(ch[i].y), TotalOrd(ch[i].x), i))
        .min()
        .unwrap()
        .2;
    println!("{}", n);
    for i in 0..n {
        let k = (i + j) % n;
        println!("{} {}", ch[k].x, ch[k].y);
    }
}



Measured memory_bytes: 11076