Problem:
Convex Hull

Find the convex hull of a given set of points P. In other words, find the smallest convex polygon containing all the points of P. Here, in a convex polygon, all interior angles are less than or equal to 180 degrees.

Please note that you should find all the points of P on both corner and boundary of the convex polygon.

Input

n
x1 y1
x2 y2
:
xn yn

The first integer n is the number of points in P. The coordinate of the i-th point pi is given by two integers xi and yi.

Output

In the first line, print the number of points on the corner/boundary of the convex polygon. In the following lines, print x y coordinates of the set of points.
The coordinates should be given in the order of counter-clockwise visit of them starting from the point in P with the minimum y-coordinate, or the leftmost such point in case of a tie.

Constraints

3 ≤ n ≤ 100000

-10000 ≤ xi, yi ≤ 10000

No point in the P will occur more than once.

Sample Input 1

7
2 1
0 0
1 2
2 2
4 2
1 3
3 3

Sample Output 1

5
0 0
2 1
4 2
3 3
1 3

Sample Input 2

4
0 0
2 2
0 2
0 1

Sample Output 2

4
0 0
2 2
0 2
0 1

Solution in C# (judge verdict: Accepted)

using System;
using System.Linq;//リストの使用
using System.Collections.Generic;
class Program
{
	static void Main()
	{
		long n = long.Parse(Console.ReadLine());
    Vector2[] polygon = new Vector2[n];

    for(long i = 0; i < n; i++)
    {
      string[] input = Console.ReadLine().Split(' ');
      polygon[i] = new Vector2(decimal.Parse(input[0]), decimal.Parse(input[1]));
    }
    List<Vector2> answers = Vector2.ConvexHull(polygon);
    
    Console.WriteLine(answers.Count());
    for(int i = 0; i < answers.Count(); i++)
    {
      Console.WriteLine(answers[i].x + " " + answers[i].y);
    }
	}
}

class Vector2//2次元ベクトル
{
static decimal EPS = 1e-10m;//小数誤差比較

  public Vector2 (decimal X, decimal Y)
  {
    this.x = X;
    this.y = Y;
  }

  public decimal x {private set; get;}
  public decimal y {private set; get;}

  public static Vector2 operator + (Vector2 ob1, Vector2 ob2)//ベクトルの基本演算
  {
    return new Vector2 (ob1.x + ob2.x, ob1.y + ob2.y);
  }
  public static Vector2 operator - (Vector2 ob1, Vector2 ob2)
  {
    return new Vector2 (ob1.x - ob2.x, ob1.y - ob2.y);
  }
  public static Vector2 operator * (Vector2 ob, decimal scalar)
  {
    return new Vector2 (ob.x * scalar, ob.y * scalar);
  }
  public static Vector2 operator * (decimal scalar, Vector2 ob)
  {
    return new Vector2 (ob.x * scalar, ob.y * scalar);
  }
  public static Vector2 operator / (Vector2 ob, decimal scalar)
  {
    return new Vector2 (ob.x / scalar, ob.y / scalar);
  }

  public decimal Length()//ベクトルの長さの2乗
  {
    return x * x + y * y;
  }
  public static decimal Distance(Vector2 ob1, Vector2 ob2)//2点間の距離
  {
    return (decimal)Math.Sqrt((double)((ob1.x-ob2.x) * (ob1.x-ob2.x) + (ob1.y-ob2.y) * (ob1.y-ob2.y)));
  }
  public static decimal DotProduct(Vector2 ob1, Vector2 ob2)//内積
  {
    return ob1.x * ob2.x + ob1.y * ob2.y;
  }
  public static decimal CrossProduct(Vector2 ob1, Vector2 ob2)//外積。第2引数が反時計回り側で正。
  {
    return ob1.x * ob2.y - ob1.y * ob2.x;
  }
  public static decimal Arg(Vector2 p)//x軸に対する偏角
  {
    return (decimal)Math.Atan2((double)p.y, (double)p.x);
  }
  public static Vector2 PoralCoordinate(decimal radius, decimal angle)//長さと座標から極座標にする
  {
    return new Vector2(radius * (decimal)Math.Cos((double)angle), radius * (decimal)Math.Sin((double)angle));
  }

  public static Vector2 Projection(Vector2 beginPoint, Vector2 endPoint, Vector2 point)//点の射影
  {
    Vector2 segment = endPoint - beginPoint;
    decimal ratio = Vector2.DotProduct(point - beginPoint, segment) / segment.Length();
    return beginPoint + segment * ratio;//始点にたす
  }

public static long WhereVector(Vector2 beginPoint, Vector2 endPoint, Vector2 point)
  {//ベクトルに対する点の位置
    Vector2 segment = endPoint - beginPoint;
    Vector2 aimVec = point - beginPoint;
    if(Vector2.CrossProduct(segment, aimVec) > EPS)
      return 1;//反時計回り側
    else if(Vector2.CrossProduct(segment, aimVec) < -EPS)
      return 2;//時計回り側
    else if(Vector2.DotProduct(segment, aimVec) < -1+EPS)
      return 3;//ベクトル反対向きの側
    else if(segment.Length() < aimVec.Length())
      return 4;//ベクトル向きの側
    else
      return 5;//ベクトル上
  }

    public static List<Vector2> ConvexHull(Vector2[] polygon)//凸包を左下から反時計回りに返す
    {
      int n = polygon.Length;
      
      decimal[][] polygonArraySub = new decimal[n][];
      for(int i = 0; i < n; i++)
      {
        polygonArraySub[i] = new decimal[2];
        polygonArraySub[i][0] = polygon[i].x;
        polygonArraySub[i][1] = polygon[i].y;
      }
      var sorted = polygonArraySub.OrderBy(a => a[1]).ThenBy(a => a[0]).ToList();
      for(int i = 0; i < n; i++)
      {
        polygon[i] = new Vector2(sorted[i][0], sorted[i][1]);
      }
      
      List<Vector2> listUp = new List<Vector2>();//凸包の上側
      List<Vector2> listDown = new List<Vector2>();//凸包の下側
      List<Vector2> listAnswer = new List<Vector2>();//凸包

      if(n == 1)
      {
        listAnswer.Add(polygon[0]);
        return listAnswer;
      }else if(n == 2)
      {
        listAnswer.Add(polygon[0]);
        listAnswer.Add(polygon[1]);
        return listAnswer;
      }

      listUp.Add(polygon[0]);
      listUp.Add(polygon[1]);
      listDown.Add(polygon[n-1]);
      listDown.Add(polygon[n-2]);

      for(int i = 2; i < n; i++)
      {//凸包の上側を作成
        for(int j = listUp.Count(); j >= 2 &&
          WhereVector(listUp[j-2], listUp[j-1], polygon[i]) == 1; j--)
        {
          //Console.WriteLine(listUp[listUp.Count()-1].x+"r"+listUp[listUp.Count()-1].y);
          listUp.RemoveAt(listUp.Count()-1);
        }
        listUp.Add(polygon[i]);
      }

      for(int i = n-3; i >= 0; i--)
      {//凸包の下側を作成
        for(int j = listDown.Count(); j >= 2 &&
          WhereVector(listDown[j-2], listDown[j-1], polygon[i]) == 1; j--)
        {
          listDown.RemoveAt(listDown.Count()-1);
        }
        listDown.Add(polygon[i]);
      }

      for(int i = listDown.Count()-1; i >= 0; i--)//時計回りにする
      {
        listAnswer.Add(listDown[i]);
        //Console.WriteLine(listDown[i].x+"d"+listDown[i].y);
      }
      for(int i = listUp.Count()-2; i >= 1; i--)//時計回りにする
      {
        listAnswer.Add(listUp[i]);
        //Console.WriteLine(listUp[i].x+"u"+listUp[i].y);
      }
      
      return listAnswer;
    }
}