Problem:
Problem H: Magic Walls

You are a magician and have a large farm to grow magical fruits.

One day, you saw a horde of monsters, approaching your farm. They would ruin your magical farm once they reached your farm. Unfortunately, you are not strong enough to fight against those monsters. To protect your farm against them, you decided to build magic walls around your land.

You have four magic orbs to build the walls, namely, the orbs of Aquamarine (A), Bloodstone (B), Citrine (C) and Diamond (D). When you place them correctly and then cast a spell, there will be magic walls between the orbs A and B, between B and C, between C and D, and between D and A. The walls are built on the line segments connecting two orbs, and form a quadrangle as a whole. As the monsters cannot cross the magic walls, the inside of the magic walls is protected.

Nonetheless, you can protect only a part of your land, since there are a couple of restrictions on building the magic walls. There are N hills in your farm, where the orbs can receive rich power of magic. Each orb should be set on the top of one of the hills. Also, to avoid interference between the orbs, you may not place two or more orbs at the same hill.

Now, you want to maximize the area protected by the magic walls. Please figure it out.

Input

The input begins with an integer N (4 ≤ N ≤ 1500), the number of the hills. Then N line follow. Each of them has two integers x (0 ≤ x ≤ 50000) and y (0 ≤ y ≤ 50000), the x- and y-coordinates of the location of a hill.

It is guaranteed that no two hills have the same location and that no three hills lie on a single line.

Output

Output the maximum area you can protect. The output value should be printed with one digit after the decimal point, and should be exact.

Sample Input 1

5
2 0
0 1
1 3
4 2
3 4

Output for the Sample Input 1

7.5

Sample Input 2

4
0 0
0 3
1 1
3 0

Output for the Sample Input 2

3.0

Solution in C++ (judge verdict: Accepted)

#include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-6)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0

using namespace std;

class Point{
public:
  double x,y;
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

Polygon andrewScan(Polygon s) {
  Polygon u,l;
  if(s.size() < 3)return s;

  sort(s.begin(),s.end());

  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++) {
      for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
        u.pop_back();
      u.push_back(s[i]);
    }

  for(int i=s.size()-3; i>=0 ; i--) {
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
        l.pop_back();
      l.push_back(s[i]);
    }

  reverse(l.begin(),l.end());

  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);

  return l;
}

inline double heron(Point A,Point B,Point C){
  double a = abs(B-C);
  double b = abs(A-C);
  double c = abs(A-B);
  double s = ( a + b + c ) / 2;
  return sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
}

// -----------------------------------------------------------

const int MAX_V = 1510;
int V,nV;
vector<Point> ps,nps;

bool LT(double a,double b) { return !equals(a,b) && a < b; }
bool LTE(double a,double b) { return equals(a,b) || a < b; }

static const double RATIO = ( 1 + sqrt(5.0) ) * 0.5;
double ternarySearch(int a,int b){
  int L = 1, R = ( a > b ) ? ( ( a - b - 1 + nV ) % nV ) : ( ( ( a + nV ) - b - 1  ) % nV );
  int sp = b;
  int pL = L, pR = R;


  rep(_,120){
    if( LT(heron(nps[((L+R*2)/3+sp)%nV],nps[a],nps[b]),heron(nps[((L*2+R)/3+sp)%nV],nps[a],nps[b])) ) {
      R = ( L + R * 2 ) / 3;
    } else {
      L = ( L * 2 + R ) / 3;
    }
    if( R == pR && L == pL ) break;
    pR = R, pL = L;
  }

  /*
  double Lv = heron(nps[a],nps[b],nps[((int)((L*RATIO+R)/(1+RATIO))+sp)%nV]);
  double Rv = heron(nps[a],nps[b],nps[((int)((L+R*RATIO)/(1+RATIO))+sp)%nV]);
  rep(_,120){
    if( LT(Rv,Lv) ) {
      R = ( L + R * RATIO ) / ( 1 + RATIO );
      Rv = Lv;
      Lv = heron(nps[a],nps[b],nps[((int)((L*RATIO+R)/(1+RATIO))+sp)%nV]);
    } else {
      L = ( L * RATIO + R ) / ( 1 + RATIO );
      Lv = Rv;
      Rv = heron(nps[a],nps[b],nps[((int)((L+R*RATIO)/(1+RATIO))+sp)%nV]);
    }
    if( R == pR && L == pL ) break;
    pR = R, pL = L;
  }
  
  if( LT(Rv,Lv) ) R = ( L + R * RATIO ) / ( 1 + RATIO );
  else            L = ( L * RATIO + R ) / ( 1 + RATIO );
  */
  return heron(nps[(int)(((L+R)*0.5)+sp)%nV],nps[a],nps[b]);
}

void compute(){
  nps = andrewScan(ps);
  nV = nps.size();  
  double maxi = 0;
  if( nV == 3 ) {
    rep(i,V) {
      if( nps[0] == ps[i] || nps[1] == ps[i] || nps[2] == ps[i] ) continue;
      double area1 = heron(nps[0],nps[1],ps[i]);
      double area2 = heron(nps[1],nps[2],ps[i]);
      double area3 = heron(nps[2],nps[0],ps[i]);
      double area4 = heron(nps[0],nps[1],nps[2]);
      maxi = max(maxi,area4-min(area1,min(area2,area3)));
    }
  } else {
    rep(i,nV) REP(j,i+2,nV) maxi = max(maxi,ternarySearch(i,j)+ternarySearch(j,i));
  }
  printf("%.1f\n",maxi);
}

int main(){
  scanf("%d",&V);
  ps.resize(V);
  rep(i,V) scanf("%lf %lf",&ps[i].x,&ps[i].y);
  compute();
  return 0;
}