Problem:
Problem D: Exportation in Space
In an era of space travelling, Mr. Jonathan A. Goldmine exports a special
material named "Interstellar Condensed Powered Copper". A piece of it consists
of several spheres floating in the air. There is strange force affecting between
the spheres so that their relative positions of them are not changed. If you
move one of them, all the others follow it.
Example of ICPC (left: bare, right: shielded)
To transport ICPCs between planets, it needs to be shielded from cosmic
rays. It will be broken when they hit by strong cosmic rays. Mr. Goldmine needs
to wrap up each ICPC pieces with anti-cosmic-ray shield, a paper-like material
which cuts all the cosmic rays. To save cost, he wants to know the minimum area
of the shield he needs to wrap an ICPC piece up.
Note that he can't put the shield between the spheres of an ICPC because
it affects the force between the spheres. So that the only way to shield it is
to wrap the whole ICPC piece by shield.
Mr. Goldmine asked you, an experienced programmer, to calculate the
minimum area of shield for each material.
You can assume that each sphere in an ICPC piece is a point, and you can
ignore the thickness of the shield.
Input
Each file consists of one test case, which has the information of one
ICPC piece. A test case starts with a line with an integer
N
(4 <=
N
<= 50), denoting the number of spheres in the piece of the test case. Then
N
lines follow. The
i
-th line of them describes the position of the
i
-th
sphere. It has 3 integers
x
i
,
y
i
and
z
i
(0 <=
x
,
y
,
z
<= 100),
separated by a space. They denote the
x
,
y
and
z
coordinates of the
i
-th sphere, respectively.
It is guaranteed that there are no data all of whose spheres are on the
same plane, and that no two spheres in a data are on the same coordinate.
Output
For each input, print the area of the shield Mr. Goldmine needs. The
output value should be in a decimal fraction and should not contain an error greater than 0.001.
Sample Input 1
4
0 0 0
0 0 1
0 1 0
1 0 0
Output for the Sample Input 1
2.366
Sample Input 2
8
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
Output for the Sample Input 2
6.000

Submitted solutions:

code_snippet: #include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <complex>
using namespace std;
const double EPS = 1e-10;
const double INF = 1e12;
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}

double getarea(const VP &poly){
    double ret = 0;
    for (int i=0; i<(int)poly.size(); i++){ 
        ret += cross(poly[i], poly[(i+1)%poly.size()]);
    }
    return ret*0.5;
}
VP convex(VP v){
    VP ret;
    int n = v.size();
    sort(v.begin(), v.end());
    for(int i=0; i<n; i++){
        while((int)ret.size()>1 && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    int t = ret.size();
    for(int i=n-2; i>=0; i--){
        while((int)ret.size()>t && cross(ret.back()-ret[ret.size()-2], v[i]-ret.back()) < EPS){
            ret.pop_back();
        }
        ret.push_back(v[i]);
    }
    if((int)ret.size() > 1) ret.pop_back();
    return ret;
}

struct Point{
    double x,y,z;
    Point(double x, double y, double z):x(x), y(y), z(z){}
    Point(){}
    Point &operator +=(const Point &a){ x+=a.x; y+=a.y; z+=a.z; return *this; }
    Point &operator -=(const Point &a){ x-=a.x; y-=a.y; z-=a.z; return *this; }
    Point &operator *=(const double &a){ x*=a; y*=a; z*=a; return *this; }
    Point operator +(const Point &a) const{ return Point(x+a.x, y+a.y, z+a.z); }
    Point operator -(const Point &a) const{ return Point(x-a.x, y-a.y, z-a.z); }
    Point operator *(const double &a) const{ return Point(a*x, a*y, a*z); }
    Point operator -() { return Point(-x, -y, -z); }
};
 
double dot(const Point &a, const Point &b){
    return a.x*b.x +a.y*b.y +a.z*b.z;
}
Point cross(const Point &a, const Point &b){
    return Point(a.y*b.z -a.z*b.y, a.z*b.x -a.x*b.z, a.x*b.y -a.y*b.x);
}
double abs(const Point &a){
    return sqrt(dot(a, a));
}
Point unit(const Point &a){
    return a *(1/abs(a));
}
bool operator ==(const Point &a, const Point &b){
    return abs(a-b) < EPS;
}

//2次元に転写して凸包の面積を出す
double convex_area(const vector<Point> &p, Point normal){
    VP p2d;
    Point base = p[1] -p[0];
    p2d.emplace_back(0, 0);
    p2d.emplace_back(abs(base), 0);
    for(int i=2; i<(int)p.size(); i++){
        Point v = p[i] -p[0];
        double theta = acos(dot(base, v)/(abs(base)*abs(v)));
        if(dot(cross(base, v), normal) > 0){
            theta *= -1;
        }
        p2d.push_back(P(abs(v), 0) *P(cos(theta), sin(theta)));
    }
    return getarea(convex(p2d));
}

int main(){
    int n;
    cin >> n;
    vector<Point> p(n);
    for(int i=0; i<n; i++){
        cin >> p[i].x >> p[i].y >> p[i].z;
    }

    bool used[50][50][50];
    memset(used, false, sizeof(used));
    double ans = 0;
    //点を3つ選ぶ
    for(int i=0; i<n; i++){
        for(int j=i+1; j<n; j++){
            for(int k=j+1; k<n; k++){
                if(used[i][j][k]) continue;
                Point normal = cross(p[j]-p[i], p[k]-p[i]);
                if(abs(normal) < EPS) continue;
                //同じ平面上の点を列挙
                vector<int> onplane, nop;
                for(int l=0; l<n; l++){
                    if(l==i || l==j || l==k || abs(dot(normal, p[l] -p[i])) < EPS){
                        onplane.push_back(l);
                    }else{
                        nop.push_back(l);
                    }
                }
                int m = onplane.size();
                for(int s=0; s<m; s++){
                    for(int t=s+1; t<m; t++){
                        for(int u=t+1; u<m; u++){
                            used[onplane[s]][onplane[t]][onplane[u]] = true;
                        }
                    }
                }
                //平面に対してすべて同じ方向にあるかどうか
                int sign = 0;
                for(int s=0; s<(int)nop.size(); s++){
                    double d = dot(normal, p[nop[s]] -p[i]);
                    if((sign==1 && d<0) || (sign==-1 && d>0)){
                        sign = 0;
                        break;
                    }
                    if(d > 0) sign = 1;
                    else sign = -1;
                }
                if(sign != 0){
                    vector<Point> plist;
                    for(int i=0; i<(int)onplane.size(); i++){
                        plist.push_back(p[onplane[i]]);
                    }
                    ans += convex_area(plist, normal);
                }
            }
        }
    }
    cout << fixed << setprecision(10);
    cout << ans << endl;
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3788
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}

bool isParallel2(Vector a,Vector b){
 
  return (  dot(a,b) > eps && abs(cross(a,b)) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt(1.0 - co * co);

    if( isParallel2( cross(t[i]-t[0],base) , cross(base,t[i]-t[0]) ) ){
      cout<<'!'<<endl;
    }
    
    if( i == 2 || isParallel2(cross(t[i]-t[0],base),ex)){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
         if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
         Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;          
        if(used[g])continue;
        used[g]=true;
        T.push_back(g);
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1296
final_rank: 1

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}

bool isParallel2(Vector a,Vector b){
  a = a * (1.0/ abs(a));
  b = b * (1.0/ abs(b));
  return ( eq(a.x,b.x) && eq(a.y,b.y) );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt(1.0 - co * co);

    
    if( i == 2 || isParallel2(cross(t[i]-t[0],base),ex)){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
         if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
         Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;          
        if(used[g])continue;
        used[g]=true;
        T.push_back(g);
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-10;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}

bool isParallel2(Vector a,Vector b){
  a = a * (1.0/ abs(a));
  b = b * (1.0/ abs(b));
  return ( eq(a.x,b.x) && eq(a.y,b.y) );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt(1.0 - co * co);

    
    if( i == 2 || isParallel2(cross(t[i]-t[0],base),ex)){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
         if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
         Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;          
        if(used[g])continue;
        used[g]=true;
        T.push_back(g);
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-10;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt(1.0 - co * co);

    
    if( i == 2 || eq( 0 , abs(  cross( ex , cross(t[i]-t[0],base) )) )){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
         if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
         Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;          
        if(used[g])continue;
        used[g]=true;
        T.push_back(g);
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1296
final_rank: 12

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-10;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = abs( cross(t[i]-t[0],base ) ) / abs(t[i]-t[0]) / abs(base) ;

    
    if( i == 2 || eq( 0 , abs(  cross( ex , cross(t[i]-t[0],base) )) )){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  vector< long long > t2;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
 
        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
 
         
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
          
        if(!used[g]){
          used[g]=true;
          long long bit=0;
          for(int l=0;l<(int)g.size();l++){
            bit|=(1LL<<g[l]);
          }
          t2.push_back(bit);
          T.push_back(g);
        }
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = abs( cross(t[i]-t[0],base ) ) / abs(t[i]-t[0]) / abs(base) ;

    
    if( i == 2 || eq( 0 , abs(  cross( ex , cross(t[i]-t[0],base) )) )){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  vector< long long > t2;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
 
        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
 
         
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
          
        if(!used[g]){
          used[g]=true;
          long long bit=0;
          for(int l=0;l<(int)g.size();l++){
            bit|=(1LL<<g[l]);
          }
          t2.push_back(bit);
          T.push_back(g);
        }
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-8;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = abs( cross(t[i]-t[0],base ) ) / abs(t[i]-t[0]) / abs(base) ;

    
    if( i == 2 || eq( 0 , abs(  cross( ex , cross(t[i]-t[0],base) )) )){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  vector< long long > t2;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
 
        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
 
         
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
          
        if(!used[g]){
          used[g]=true;
          long long bit=0;
          for(int l=0;l<(int)g.size();l++){
            bit|=(1LL<<g[l]);
          }
          t2.push_back(bit);
          T.push_back(g);
        }
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-20;
pair<double,int> Pair;
  
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
  
struct Point{
  double x,y,z;
    
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
    
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
    
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
  
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
  
  
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
  
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
  
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
  
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
  
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
  
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
  
struct Segment{
  Point p, v;
};
typedef Segment Line;
  
struct Plane{
  Point p, v1, v2;
};
  
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
  
  
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
    
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
  
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
  
  
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
  
  
  
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
  
  
int ccw( Point p0 , Point p1 , Point p2 ) {
    
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
  
  
  
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
  
  if(size < 3) return s;
  sort(s.begin(),s.end());
  
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
  
  for(int i = 2 ; i < 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 = 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;
}
  
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
  
  Vector ex = cross(t[2]-t[0],base);
  
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = abs( cross(t[i]-t[0],base ) ) / abs(t[i]-t[0]) / abs(base) ;

    
    if( i == 2 || eq( 0 , abs(  cross( ex , cross(t[i]-t[0],base) )) )){
      si*=-1.0;
    }

  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
  
  vector<Point> res= andrewScan(b);
   
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
  
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  vector< long long > t2;
    
  int n;
  cin>>n;
  vector<Point> G(n);
   
  for(int i=0;i<n;i++)scan(G[i]);
    
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){
 
        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;
 
         
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
          
        if(!used[g]){
          used[g]=true;
          long long bit=0;
          for(int l=0;l<(int)g.size();l++){
            bit|=(1LL<<g[l]);
          }
          t2.push_back(bit);
          T.push_back(g);
        }
      }
    }
  }
  
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
  
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #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-7)
#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;
}



Point crosspoint(Line l,Line m){
  double A = cross(l.p2-l.p1,m.p2-m.p1);
  double B = cross(l.p2-l.p1,l.p2-m.p1);
  if( abs(A) < EPS && abs(B) < EPS ){
	vector<Point> vec;
	vec.push_back(l.p1);
	vec.push_back(l.p2);
	vec.push_back(m.p1);
	vec.push_back(m.p2);
	sort(vec.begin(),vec.end());
	assert(vec[1] == vec[2]);
	return vec[1];
  }
  if( abs(A) < EPS ) assert(false);
  return m.p1 + (m.p2-m.p1) * (B/A);
}

Polygon cutPolygon( Polygon P, Line l ){
    Polygon u;
    for ( int i = 0; i < P.size(); i++ ){
        Point a = P[i], b = P[(i+1)%P.size()];
        if ( ccw(l.p1, l.p2, a) != CLOCKWISE ) u.push_back(a);
	 //if( ccw(l.p1,l.p2,a) != COUNTER_CLOCKWISE ) R.push_back(a); // ????????????????????´???
        if ( ccw(l.p1, l.p2, a) * ccw(l.p1, l.p2, b) == -1 ){
      u.push_back(crosspoint(Segment(a, b), l));
        }
    }
    return u;
}



//????????? Verify??????????????????Verify??¨???????????????
 
//Verify AOJ 0115
class Point3d{
public:
  double x,y,z;
 
  Point3d(double x=0,double y=0,double z=0):x(x),y(y),z(z){}
 
  Point3d operator + (const Point3d& a){
    return Point3d(x+a.x,y+a.y,z+a.z);
  }
  Point3d operator - (const Point3d& a){
    return Point3d(x-a.x,y-a.y,z-a.z);
  }
  Point3d operator * (const double& d){
    return Point3d(x*d,y*d,z*d);
  }
  Point3d operator / (const double& d){
    return Point3d(x/d,y/d,z/d);
  }
 
  bool operator < (const Point3d& p)const { return !equals(x,p.x)?x<p.x:((!equals(y,p.y))?y<p.y:(!equals(z,p.z)&&z<p.z)); }
 
  bool operator == (const Point3d& p)const{
    return equals(x,p.x) && equals(y,p.y) && equals(z,p.z);
  }
 
};
 
//Verify AOJ 0115
struct Segment3d{
  Point3d p[2];
  Segment3d(Point3d p1=Point3d(),Point3d p2=Point3d()){
    p[0] = p1, p[1] = p2;
  }
 bool operator == (const Segment3d& seg)const{
    return ( p[0] == seg.p[0] && p[1] == seg.p[1] ) || ( p[0] == seg.p[1] && p[1] == seg.p[0] );
 }
};
 
typedef Point3d Vector3d;
typedef Segment3d Line3d;
  
ostream& operator << (ostream& os,const Point3d& p){
  os << "(" << p.x << "," << p.y << "," << p.z << ")";
}
 
ostream& operator << (ostream& os,const Segment3d& seg){
  os << "(" << seg.p[0] << "," << seg.p[1] << ")";
}
 
//Verify AOJ 0115
double dot(const Point3d& a,const Point3d& b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
//Verify AOJ 0115
Vector3d cross(const Point3d& a,const Point3d& b){
  return Vector3d(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
 
//Verify AOJ 0115
inline double norm(const Point3d &p){
  return p.x*p.x + p.y*p.y + p.z*p.z;
}
 
//Verify AOJ 0115
inline double abs(const Point3d &p){
  return sqrt(norm(p));
}
 
inline double toRad(double theta){
  return theta * M_PI / 180.0;
}
 
 
 // Verify AOJ 1331
bool on_line3d(Line3d line,Point3d p){
  return equals(abs(cross(p-line.p[0],line.p[1]-line.p[0])),0);
}
 
// Verify AOJ 1331
bool on_segment3d(Segment3d seg,Point3d p){
  if( !on_line3d(seg,p) ) return false;
  double dist[3] = { abs(seg.p[1]-seg.p[0]), abs(p-seg.p[0]), abs(p-seg.p[1]) };  
  return on_line3d(seg,p) && equals(dist[0],dist[1]+dist[2]);
}
 
//Verify AOJ 0115
bool point_on_the_triangle3d(Point3d tri1,Point3d tri2,Point3d tri3,Point3d p){
 
  //????????????p????????£?????´??????????§???¢?????¨?????????
  //if( on_segment3d(Segment3d(tri1,tri2),p) ) return true;
  //if( on_segment3d(Segment3d(tri2,tri3),p) ) return true;
  //if( on_segment3d(Segment3d(tri3,tri1),p) ) return true;

  vector<Point3d> vec(3);
  vec[0] = tri1, vec[1] = tri2, vec[2] = tri3;
  double area = 0;
  {
    double a = abs(vec[0]-vec[1]), b = abs(vec[1]-vec[2]), c = abs(vec[2]-vec[0]);
    double s = ( a + b + c ) / 2;
    area = sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
  }
  double sum = 0;
  rep(i,3){
    double a = abs(vec[i]-vec[(i+1)%3]), b = abs(vec[(i+1)%3]-p), c = abs(p-vec[i]);
    double s = ( a + b + c ) / 2;
    sum += sqrt( s * ( s - a ) * ( s - b ) * ( s - c ) );
  }
  return equals(sum,area);

// ---------- ??\???????????°????????¨???????????? ---------

  Vector3d v1 = tri2 - tri1;
  Vector3d v2 = tri3 - tri2;
  Vector3d v3 = tri1 - tri3;
 
  Vector3d cp[3] = { cross(v1,p-tri1), cross(v2,p-tri2), cross(v3,p-tri3) };
  double d1 = dot(cp[0],cp[1]);
  double d2 = dot(cp[0],cp[2]);
 
  // ????????????p????????£?????´???,????§???¢?????¨??????????????????
  //if( ( !equals(d1,0.0) && d1 > 0 ) && ( !equals(d2,0.0) && d2 > 0 ) ) return true;
 
  // ????????????p????????£?????´???,????§???¢?????¨?????????
  if( ( equals(d1,0.0) || d1 > 0 ) && ( equals(d2,0.0) || d2 > 0 ) ) return true;
  return false;
}
 
inline Point3d rotateX(Point3d p,double rad){
  return Point3d(p.x,p.y*cos(rad)-p.z*sin(rad),p.y*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rotateY(Point3d p,double rad){
  return Point3d(p.x*cos(rad)+p.z*sin(rad),p.y,-p.x*sin(rad)+p.z*cos(rad));
}
 
inline Point3d rotateZ(Point3d p,double rad){
  return Point3d(p.x*cos(rad)-p.y*sin(rad),p.x*sin(rad)+p.y*cos(rad),p.z);
}
 
inline Point3d rotateEuler(Point3d p,double alpha,double beta,double gamma){
  return Point3d( (cos(alpha)*cos(beta)*cos(gamma)-sin(alpha)*sin(gamma)) * p.x + (-cos(alpha)*cos(beta)*sin(gamma)-sin(alpha)*cos(gamma)) * p.y + (cos(alpha)*sin(beta)) * p.z,
		  (sin(alpha)*cos(beta)*cos(gamma)+cos(alpha)*sin(gamma)) * p.x + (-sin(alpha)*cos(beta)*sin(gamma)+cos(alpha)*cos(gamma)) * p.y + (sin(alpha)*sin(beta)) * p.z,
		  (-sin(beta)*cos(gamma)) * p.x + (sin(beta)*sin(gamma)) * p.y + (cos(beta)) * p.z);
}
 
inline Point3d rotateRollPitchYaw(Point3d p,double roll,double pitch,double yaw){
  return Point3d( ( cos(roll) * cos(pitch) ) * p.x + ( cos(roll) * sin(pitch) * sin(yaw) - sin(roll) * cos(yaw) ) * p.y + ( cos(roll) * sin(pitch) * cos(yaw) + sin(roll) * sin(yaw) ) * p.z,
		  ( sin(roll) * cos(pitch) ) * p.x + ( sin(roll) * sin(pitch) * sin(yaw) + cos(roll) * cos(yaw) ) * p.y + ( sin(roll) * sin(pitch) * cos(yaw) - cos(roll) * sin(yaw) ) * p.z,
		  -sin(pitch) * p.x + cos(pitch) * sin(yaw) * p.y + cos(pitch) * cos(yaw) * p.z);
}
 
 
class Plane3d{
public:
  Point3d normal_vector; //??????????????????
  double d; // ?????¢????¨???? normal_vector.x * x + normal_vector.y * y + normal_vector.z * z + d = 0
 
  Plane3d(Point3d normal_vector=Point3d(),double d=0):normal_vector(normal_vector),d(d){}
  Plane3d(Vector3d a,Vector3d b,Vector3d c){
    Vector3d v1 = b - a;
    Vector3d v2 = c - a;
    Vector3d tmp = cross(v1,v2);
    normal_vector = tmp / abs(tmp);
    set_d(a);
  }
 
  //Verify AOJ 0115
  //??????????????????normal_vector??¨?????¢??????????????????d????¨??????????
  void set_d(Point3d p){
    d = dot(normal_vector,p);
  }
 
// Verify Yukicoder No132
  //?????¢??¨???p????????¢????±???????
  double distanceP(Point3d p){
    Point3d a = normal_vector * d;//?????¢??????????????????????????????
    return abs( dot(p-a,normal_vector) );
  }

  double distanceP2(Point3d p){
    Point3d a = normal_vector * d;//?????¢??????????????????????????????
    return dot(p-a,normal_vector);
  } 

  //?????¢?????§?????£??¨??????p??¨?????????????±???????
  Point3d nearest_point(Point3d p){
    Point3d a = normal_vector * d;
    return p - ( normal_vector * dot(p-a,normal_vector) );
  }
 
  //Verify AOJ 0115
  //?????¢??¨????????????????????????
  bool intersectS(Segment3d seg){
    Point3d a = normal_vector * d;
    double res1 = dot(a-seg.p[0],normal_vector);
    double res2 = dot(a-seg.p[1],normal_vector);
    if( res1 > res2 ) swap(res1,res2);
    //cout << res1 << " < " << res2 << endl;
    if( ( equals(res1,0.0) || res1 < 0 ) && ( equals(res2,0.0) || res2 > 0 ) ) return true;
    return false;
  }
 
  //Verify AOJ 0115
  //?????¢??¨???????????????????±???????
  Point3d crosspointS(Segment3d seg){
    Point3d a = normal_vector * d;
    double dot_p0a = fabs(dot( seg.p[0]-a,normal_vector ));
    double dot_p1a = fabs(dot( seg.p[1]-a,normal_vector ));
    if( equals(dot_p0a+dot_p1a,0) ) return seg.p[0];
    return seg.p[0] + ( seg.p[1] - seg.p[0] ) * ( dot_p0a / ( dot_p0a + dot_p1a ) );
  }
 
};
 
double distanceLP(Line3d line,Point3d p){
  return abs(cross(line.p[1]-line.p[0],p-line.p[0])) / abs(line.p[1]-line.p[0]);
}
 
// Verify AOJ 1331
Point3d project(Segment3d seg,Point3d p){
  Vector3d base = seg.p[1] - seg.p[0];
  double t = dot(p-seg.p[0],base) / norm(base);
  return seg.p[0] + base * t;
}
 
// Verify AOJ 1331
Point3d reflect(Segment3d seg,Point3d p){
  return p + (project(seg,p)-p) * 2.0;
}

// Verify AOJ 1331
double distanceSP(Segment3d seg,Point3d p){
  Point3d r = project(seg,p);
  if( on_segment3d(seg,r) ) return abs(p-r);
  return min(abs(seg.p[0]-p),abs(seg.p[1]-p));
}

//Verify AOJ 2081
bool isParallel(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
  return equals(tmp,0.0);
}
 
//Verify AOJ 2081 
//l1,l2??????????????????????????¨??§??????????????§??¨???
Segment3d nearest_segmentLL(Line3d l1,Line3d l2){
  assert(!isParallel(l1,l2)); // ???????????´???????????¨??????
  // l1.p[0] = A, l1.p[1] = B, l2.p[0] = C, l2.p[1] = D
  Vector3d AB = l1.p[1] - l1.p[0];
  Vector3d CD = l2.p[1] - l2.p[0];
  Vector3d AC = l2.p[0] - l1.p[0];
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double d1 = (dot(n1,AC)-dot(n1,n2)*dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  double d2 = (dot(n1,n2)*dot(n1,AC)-dot(n2,AC)) / (1.0-pow(dot(n1,n2),2));
  return Segment3d(l1.p[0]+n1*d1,l2.p[0]+n2*d2);
}
 
//Verify AOJ 2081
bool intersectLL(Line3d l1,Line3d l2){
  Vector3d A = l1.p[0], B = l1.p[1], C = l2.p[0], D = l2.p[1];
 
  //????????????l1,l2?????´???????????????
  if( equals(abs(B-A),0.0) || equals(abs(D-C),0.0) ){
    /*
      ????????´????????¨???
      ??????????????????????????????????????????????????£?????????????????§??????????????????????????????????????§?????????
    */
    return false;
  }
 
  Vector3d AB = B - A, CD = D - C;
  Vector3d n1 = AB / abs(AB), n2 = CD / abs(CD);
  double tmp = dot(n1,n2);
  tmp = 1 - tmp*tmp;
 
  if( equals(tmp,0.0) ) return 0; // ??´????????????
 
  Segment3d ns = nearest_segmentLL(l1,l2);
  if( ns.p[0] == ns.p[1] ) return true;
  return false;
}

bool intersectSS(Segment3d seg1,Segment3d seg2){
  if( isParallel(seg1,seg2) ) return false;
  Segment3d seg = nearest_segmentLL(seg1,seg2);
  if( !( seg.p[0] == seg.p[1] ) ) return false;
  Point3d cp = seg.p[1];
  return on_segment3d(seg1,cp) && on_segment3d(seg2,cp);
}

typedef pair<Point3d,bool> P3db;

/* 
??????AOJ2562??§Verify???????????????????????§??\???????????§?????????????????????????????¨
Input:
??????????????¢pl1,pl2
Output:
??????????????¢????????????????????´???     -> first:???????????????????????????, second:true
?????????????????????????????????????????´??? -> first:empty            , second:false

 */
P3db intersectPlPl(const Plane3d &pl1,const Plane3d &pl2){
  Vector3d v = cross(pl1.normal_vector,pl2.normal_vector);
  if( !equals(v.x,0.0) ){
    return P3db(Point3d(0,
                        (pl1.d*pl2.normal_vector.z-pl2.d*pl1.normal_vector.z)/v.x,
                        (pl1.d*pl2.normal_vector.y-pl2.d*pl1.normal_vector.y)/(-v.x)),true);
  }
  if( !equals(v.y,0.0) ){
    return P3db(Point3d((pl1.d*pl2.normal_vector.z-pl2.d*pl1.normal_vector.z)/(-v.y),
                         0,
                        (pl1.d*pl2.normal_vector.x-pl2.d*pl1.normal_vector.x)/v.y),true);
  }
  if( !equals(v.z,0.0) ){
    return P3db(Point3d((pl1.d*pl2.normal_vector.y-pl2.d*pl1.normal_vector.y)/v.z,
                        (pl1.d*pl2.normal_vector.x-pl2.d*pl1.normal_vector.x)/(-v.z),
                        0),true);
  }
  return P3db(Point3d(),false);//??????????????§?????????????????????????????¨?????????
}

/* Verify AOJ 2562
Input:
??????????????¢plane,plane2??¨?????????????????????????????????
Output:
??????????????¢?????????

??¬???:
2???????????¢???????????????????????????????????????????????????
?????¨????????????????????????????????????????????????????????????????????°??????????????????
??????????????????????????????intersectPlPl??§????????§??????
??\?????¢??????????§?????????£???????????£???
 */
Line3d intersectPlPl_converter(Plane3d plane,Plane3d plane2,Point3d tmp){
  Vector3d ve = cross(plane.normal_vector,plane2.normal_vector);
  return Line3d(tmp,tmp+(ve*10)); // ??????????????°??§?????????????????§???10
}

// x >= y
bool GTE(double x, double y){ return equals(x,y) || x > y; }

// x > y
bool GT(double x, double y){ return !equals(x,y) && x > y; }

// x < y
bool LT(double x, double y){ return !equals(x,y) && x < y; }

// x <= y
bool LTE(double x, double y){ return equals(x,y) || x < y; }



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

const int IINF = INT_MAX;
vector<Point3d> ps;
int V;

bool checkPlane(Plane3d plane,long long &bit_stream){
  int base = -IINF;
  rep(i,V) {
    if( (bit_stream>>i) & 1LL ) continue;
    double dist = plane.distanceP2(ps[i]);
    if( equals(dist,0.0) ) {
      bit_stream |= (1LL<<i);
    } else {
      int res = LT(dist,0);
      if( base == -IINF ) {
	base = res;
      } else if( base != res ) {
	return false;
      }
    }
  }
  return true;
}

pair<Point, Point> crosspointCC( Point C1, double r1, Point C2, double r2) {
  complex<double> c1(C1.x,C1.y);
  complex<double> c2(C2.x,C2.y);
  complex<double> A = conj(c2-c1), B = (r2*r2-r1*r1-(c2-c1)*conj(c2-c1)), C = r1*r1*(c2-c1);
  complex<double> D = B*B-4.0*A*C;
  complex<double> z1 = (-B+sqrt(D))/(2.0*A)+c1, z2 = (-B-sqrt(D))/(2.0*A)+c1;
  return pair<Point, Point>(Point(z1.real(),z1.imag()),Point(z2.real(),z2.imag()));
}

bool isIntersectCC(Point a,double ar,Point b,double br){
  double d = sqrt(norm(a-b));
  double r1 = max(ar,br);
  double r2 = min(ar,br);
 
  if(!equals(d,r1+r2) && d > r1+r2)return false;
  if(!equals(d,r1-r2) && d < r1-r2)return false;  // verify
  return true;
}

typedef long long ll;
vector<Point> convert3Dinto2D(ll bit_stream,Point3d a,Point3d b,Point3d c){
  vector<Point> ret;
  Point p1 = Point(0,0);
  Point p2 = Point(abs(a-b),0);
  pair<Point,Point> pp = crosspointCC(p1,abs(c-a),p2,abs(c-b));
  Point p3 = pp.first;
  if( LT(p3.y,0) ) p3 = pp.second;
  ret.push_back(p1);
  ret.push_back(p2);
  ret.push_back(p3);
  
  rep(i,V) if( (bit_stream>>i) & 1LL ) {
    if( ps[i] == a ) continue;
    if( ps[i] == b ) continue;
    if( ps[i] == c ) continue;

    double r1 = abs(ps[i]-a);
    double r2 = abs(ps[i]-b);
    double r3 = abs(ps[i]-c);
    pp = crosspointCC(p1,r1,p2,r2);
    if( equals(abs( pp.first - p3 ),r3) ) {
      ret.push_back(pp.first);
    } else {
      ret.push_back(pp.second);
    }
  }
  return ret;
}


Polygon andrewScan(vector<Point> 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;
}

double getArea(vector<Point>& vec) {
  double sum = 0;
  for(int i=0;i<vec.size();i++)
    sum += cross(vec[i],vec[(i+1)%vec.size()]);
  return fabs(sum)/2.0;
}



void compute(){
  double area = 0;
  vector<ll> vec;
  vector<Point3d> X,Y,Z;
  rep(i,V){ //
    rep(j,V){
      rep(k,V){
	Point3d v1 = ps[j] - ps[i];
	Point3d v2 = ps[k] - ps[i];
	if( equals(abs(cross(v1,v2)),0.0) ) continue;
	Plane3d plane(ps[i],ps[j],ps[k]);
	long long bit_stream = (1LL<<i) | (1LL<<j) | (1LL<<k);

  	if( checkPlane(plane,bit_stream) ) {
	  bitset<10> BIT(bit_stream);

	  vec.push_back(bit_stream);
	  X.push_back(ps[i]);
	  Y.push_back(ps[j]);
	  Z.push_back(ps[k]);

	  //cout<<BIT<<' '<<i<<' '<<j<<' '<<k<<endl;
	  //vector<Point> on_ps = convert3Dinto2D(bit_stream,ps[i],ps[j],ps[k]);
	}
      }
    }
  }
  map<ll,bool> flg;

  rep(i,(int)vec.size()){
    ll bit_stream = vec[i];
    if(flg[bit_stream])continue;
    flg[bit_stream]=true;
    vector<Point> on_ps = convert3Dinto2D(bit_stream,X[i],Y[i],Z[i]);
    //cout <<on_ps.size() << " --------" << endl;
    vector<Point> convex = andrewScan(on_ps);
    //cout <<convex.size() << " --------" << endl;
    area += getArea(convex);
  }
  printf("%.10f\n",area);
}

int main(){
  /*
  Point3d p1 = Point3d(0,0,0);
  Point3d p2 = Point3d(0,1,0);
  Point3d p3 = Point3d(0,1,1);
  Point3d p4 = Point3d(-1,0,1);
  Plane3d p(p1,p2,p3);
  cout << p.distanceP(p4) << endl;
*/

  cin >> V;
  ps.resize(V);
  rep(i,V) cin >> ps[i].x >> ps[i].y >> ps[i].z;
  compute();
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3744
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-20;
pair<double,int> Pair;
 
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
 
struct Point{
  double x,y,z;
   
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
   
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
   
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
 
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
 
 
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
 
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
 
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
 
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
 
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
 
struct Segment{
  Point p, v;
};
typedef Segment Line;
 
struct Plane{
  Point p, v1, v2;
};
 
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
 
 
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
   
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
 
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
 
 
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
 
 
 
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
 
 
int ccw( Point p0 , Point p1 , Point p2 ) {
   
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
 
 
 
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
 
  if(size < 3) return s;
  sort(s.begin(),s.end());
 
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
 
  for(int i = 2 ; i < 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 = 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;
}
 
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
 
 
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt( 1.0 - co*co);
 
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
 
  vector<Point> res= andrewScan(b);
  
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
 
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  vector< long long > t2;
   
  int n;
  cin>>n;
  vector<Point> G(n);
  
  for(int i=0;i<n;i++)scan(G[i]);
   
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){

        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;

        
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
         
        if(!used[g]){
          used[g]=true;
          long long bit=0;
          for(int l=0;l<(int)g.size();l++){
            bit|=(1LL<<g[l]);
          }
          t2.push_back(bit);
          T.push_back(g);
        }
      }
    }
  }
 
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    bool flg=false;
    for(int j=0;j<i;j++){
      long long bit=t2[i]&t2[j];
      if( __builtin_popcountll(bit) >=3 ){
        flg=true;
      }
    }

    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
 
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 1e-5;
pair<double,int> Pair;
 
bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}
 
struct Point{
  double x,y,z;
   
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
   
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
   
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }
 
  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;
 
 
void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}
 
double norm(Point p){
  return p.x*p.x+p.y*p.y+p.z*p.z;
}
 
double abs(Point p){
  return sqrt( p.x*p.x + p.y*p.y + p.z*p.z );
}
double dot(Point a,Point b){
  return a.x*b.x + a.y*b.y + a.z*b.z;
}
 
Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}
 
double cross2(Point a,Point b){
  return a.x*b.y - b.x*a.y;
}
 
bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}
 
struct Segment{
  Point p, v;
};
typedef Segment Line;
 
struct Plane{
  Point p, v1, v2;
};
 
bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}
 
 
// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
   
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}
 
void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}
 
 
vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}
 
 
 
static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;
 
 
int ccw( Point p0 , Point p1 , Point p2 ) {
   
  Vector a = p1 - p0;
  Vector b = p2 - p0;
  if( cross2(a,b) > eps ) return COUNTER_CLOCKWISE;
  if( cross2(a,b) < -eps ) return CLOCKWISE;
  if( dot(a,b) < -eps ) return ONLINE_BACK;
  if( norm(a) < norm(b) ) return ONLINE_FRONT;
  return ON_SEGMENT;
}
 
 
 
vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();
 
  if(size < 3) return s;
  sort(s.begin(),s.end());
 
  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[size-1]);
  l.push_back(s[size-2]);
 
  for(int i = 2 ; i < 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 = 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;
}
 
double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];
 
 
  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt( 1.0 - co*co);
 
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }
 
  vector<Point> res= andrewScan(b);
  
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}
 
void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
   
  int n;
  cin>>n;
  vector<Point> G(n);
  
  for(int i=0;i<n;i++)scan(G[i]);
   
  for(int i=0;i<n;i++){
    for(int j=i+1;j<n;j++){
      for(int k=j+1;k<n;k++){

        if( isParallel(G[j]-G[i],G[k]-G[i]))continue;

        
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;
         
        if(!used[g]){
          used[g]=true;
          T.push_back(g);
        }
      }
    }
  }
 
  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    double dsum=andrewscan(pol);
    sum+=dsum;
  }
  printf("%.8f\n",sum);
}
 
int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 10
memory_kb: 1292
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 0.0001;
pair<double,int> Pair;

bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}

struct Point{
  double x,y,z;
  
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
  
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
  
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }

  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;


void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}

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

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

Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}

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

bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}

struct Segment{
  Point p, v;
};
typedef Segment Line;

struct Plane{
  Point p, v1, v2;
};

bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}


// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
  
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}

void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}


vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}



static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;


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



vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();

  if(size < 3) return s;
  sort(s.begin(),s.end());

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

  for(int i = 2 ; i < 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 = 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;
}

double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];


  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt( 1.0 - co*co);

    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }

  
  //  cout<<endl;
  //for(int i=0;i<(int)b.size();i++)pr(b[i]);
  vector<Point> res= andrewScan(b);
  //for(int i=0;i<(int)res.size();i++)pr(res[i]);
  //  cout<<endl;
  
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}

void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  
  int n;
  cin>>n;
  vector<Point> G(n);
  for(int i=0;i<n;i++)scan(G[i]);
  
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      for(int k=0;k<n;k++){
        if(i==j||j==k||k==i)continue;
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        if( isParallel(a.v1,a.v2) )continue;
        
        
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;

        
        
        if(!used[g]){
          used[g]=true;
          
          T.push_back(g);
        }
      }
    }
  }

  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    /*
    for(int j=0;j<(int)pol.size();j++){
      pr(pol[j]);
    }
    cout<<endl;
    */
    double dsum=andrewscan(pol);
    //cout<<dsum<<endl;
    
    sum+=dsum;

  
  }
  printf("%.8f\n",sum);
}

int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 30
memory_kb: 1292
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 0.000001;
pair<double,int> Pair;

bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}

struct Point{
  double x,y,z;
  
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
  
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
  
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }

  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;


void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}

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

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

Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}

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

bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}

struct Segment{
  Point p, v;
};
typedef Segment Line;

struct Plane{
  Point p, v1, v2;
};

bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}


// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
  
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}

void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}


vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}



static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;


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



vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();

  if(size < 3) return s;
  sort(s.begin(),s.end());

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

  for(int i = 2 ; i < 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 = 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;
}

double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];


  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = sqrt( 1.0 - co*co);

    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }

  
  //  cout<<endl;
  //for(int i=0;i<(int)b.size();i++)pr(b[i]);
  vector<Point> res= andrewScan(b);
  //for(int i=0;i<(int)res.size();i++)pr(res[i]);
  //  cout<<endl;
  
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}

void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  
  int n;
  cin>>n;
  vector<Point> G(n);
  for(int i=0;i<n;i++)scan(G[i]);
  
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      for(int k=0;k<n;k++){
        if(i==j||j==k||k==i)continue;
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        if( isParallel(a.v1,a.v2) )continue;
        
        
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;

        
        
        if(!used[g]){
          used[g]=true;
          
          T.push_back(g);
        }
      }
    }
  }

  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    /*
    for(int j=0;j<(int)pol.size();j++){
      pr(pol[j]);
    }
    cout<<endl;
    */
    double dsum=andrewscan(pol);
    //cout<<dsum<<endl;
    
    sum+=dsum;

  
  }
  printf("%.8f\n",sum);
}

int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 30
memory_kb: 1292
final_rank: 13

code_snippet: #include<bits/stdc++.h>
using namespace std;
const double eps = 0.0000000001;
pair<double,int> Pair;

bool eq(double a,double b){
  return ( fabs(a-b) < eps );
}

struct Point{
  double x,y,z;
  
  Point operator + (Point p){
    return (Point){x+p.x,y+p.y,z+p.z};
  }
  
  Point operator - (Point p){
    return (Point){x-p.x,y-p.y,z-p.z};
  }
  
  Point operator * (double k){
    return (Point){x*k,y*k,z*k};
  }

  bool operator < (const Point &p)const{
    return ( x==p.x ? y < p.y : x < p.x );
  }
};
typedef Point Vector;


void pr(Point p){
  printf("%.5f %.5f %.5f\n",p.x,p.y,p.z);
}

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

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

Point cross(Point a,Point b){
  double nx=a.y*b.z-b.y*a.z;
  double ny=a.z*b.x-b.z*a.x;
  double nz=a.x*b.y-b.x*a.y;
  return (Point){nx,ny,nz};
}

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

bool eq(Point a,Point b){
  return ( eq(a.x,b.x) && eq(a.y,b.y) && eq(a.z,b.z) );
}

struct Segment{
  Point p, v;
};
typedef Segment Line;

struct Plane{
  Point p, v1, v2;
};

bool isParallel(Vector a,Vector b){
  return ( abs( cross(a,b) ) < eps );
}


// res==0 -> on : res==1 -> up : res==-1 -> down
int getState(Plane a,Point b){
  Vector cra = cross(a.v1,a.v2);
  double A = dot(cra,b-a.p);
  
  if( eq(A,0) )return 0;
  else if( A > 0 )return 1;
  else if( A < 0 )return -1;
  assert(1);
  return 0;
}

void scan(Point &p){
  cin>>p.x>>p.y>>p.z;
}


vector<int> check(Plane a,int n,vector<Point> &G){
  vector<int> res,tmp;
  bool f1=false,f2=false;
  for(int i=0;i<n;i++){
    int d=getState(a,G[i]);
    if(d==0){
      res.push_back(i);
    }else if(d==1){
      f1=true;
      if(f2)return tmp;
    }else if(d==-1){
      f2=true;
      if(f1)return tmp;
    }
  }
  return res;
}



static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;


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



vector<Point> andrewScan(vector<Point> s){
  vector<Point> u,l;
  int size = s.size();

  if(size < 3) return s;
  sort(s.begin(),s.end());

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

  for(int i = 2 ; i < 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 = 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;
}

double andrewscan(vector<Point> t){
  vector< Point > b;
  b.push_back((Point){0,0,0});
  b.push_back((Point){abs(t[1]-t[0]),0,0});
  Vector base = t[1]-t[0];


  for(int i=2;i<(int)t.size();i++){
    double length=abs(t[i]-t[0]);
    double co = dot(t[i]-t[0],base) / abs(t[i]-t[0]) / abs(base);
    double si = abs( cross(t[i]-t[0],base) ) / abs(t[i]-t[0]) / abs(base);
 
  
    Point d;
    d.x = co*length;
    d.y = si*length;
    d.z=0;
    b.push_back(d);
  }

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

 
  
  vector<Point> res= andrewScan(b);
  
  double sum=0;
  for(int i=1;i+1<(int)res.size();i++){
    sum+= abs( cross(res[i]-res[0],res[i+1]-res[0]) );
  }
  return sum*0.5;
}

void solve(){
  map<vector<int> , bool> used;
  vector< vector<int> > T;
  
  int n;
  cin>>n;
  vector<Point> G(n);
  for(int i=0;i<n;i++)scan(G[i]);
  
  for(int i=0;i<n;i++){
    for(int j=0;j<n;j++){
      for(int k=0;k<n;k++){
        if(i==j||j==k||k==i)continue;
        Plane a=(Plane){G[i],G[j]-G[i],G[k]-G[i]};
        if( isParallel(a.v1,a.v2) )continue;
        
        
        vector<int> g=check(a,n,G);
        if(g.size()==0)continue;

        
        
        if(!used[g]){
          used[g]=true;
          
          T.push_back(g);
        }
      }
    }
  }

  double sum=0;
  for(int i=0;i<(int)T.size();i++){
    vector<Point> pol;
    for(int j=0;j<(int)T[i].size();j++){
      pol.push_back(G[T[i][j]]);
    }
    /*
    for(int j=0;j<(int)pol.size();j++){
      pr(pol[j]);
    }
    cout<<endl;
    */
    
    sum+=andrewscan(pol);

  
  }
  printf("%.8f\n",sum);
}

int main(){
  solve();
  return 0;
}
accuracy: 0.06896551724137931
time_ms: 30
memory_kb: 1296
final_rank: 15