OI XV - tro

// https://szkopul.edu.pl/problemset/problem/oFbVh8iOGlqNYUUueTt5V9N4/site/?key=statement

#include <bits/stdc++.h>

// using namespace std;

// #define GARY_DBG
#define GARY_LIB

#define int long long

constexpr int sizik = 3001;

#define ar std::array
#define pr std::pair
#define vec std::vector

typedef vec<vec<int>> _kra;

namespace brut {
std::pair<int, int> points[sizik];
void solve(int n);
}

struct Point {
    int x, y;
    int id;
    Point(int x1, int y1, int id1) : x(x1), y(y1), id(id1) {}
    Point(int x1, int y1) : x(x1), y(y1), id(0) {}
    Point() { *this = Point(0, 0, 0); }

    // Point(int x1, int y1, int id1) : x(x1), y(y1), id(id1) {}
    Point operator+(const Point& other) const { return Point(x + other.x, y + other.y, id); }
    Point operator-(const Point& other) const { return Point(x - other.x, y - other.y, id); }
    Point& operator+=(const Point& other) {
        x += other.x;
        y += other.y;
        return *this;
    }
    Point& operator-=(const Point& other) {
        x -= other.x;
        y -= other.y;
        return *this;
    }
    bool operator==(const Point& other) const { return x == other.x && y == other.y; }
};

std::vector<Point> points;
// std::vector<Point> workshop_points;

int half_plane(const Point& p) {
    if (p.y > 0) return 1;
    if (p.y < 0) return 0;
    // y == 0
    return (p.x >= 0) ? 1 : 0;
}

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

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

int _abs(int a) {
    if (a > 0) return a;
    return -a;
}

// Compare directions (angle) of a and b without using reals.
// Returns true if angle(a) < angle(b) in [0, 2*pi) ordering.
bool angle_less(const Point& a, const Point& b) {
    int ha = half_plane(a), hb = half_plane(b);
    if (ha != hb) return ha > hb; // upper half-plane comes first
    int cr = cross(a, b);
    if (cr != 0) return cr > 0; // a before b if cross>0 (b is ccw from a)
    // collinear same ray direction: tie-break deterministically by distance
    // (closer first) — optional; it won't affect direction-only logic
    int da = a.x * a.x + a.y * a.y;
    int db = b.x * b.x + b.y * b.y;
    return da < db;
}

// zwraca true jeśli angle(u,v) < angle(p,q)
// Returns true if the CCW angle from u to v is < CCW angle from p to q
bool angle_less2(const Point& u, const Point& v, const Point& p, const Point& q) {
    int c1 = cross(u, v);
    int c2 = cross(p, q);
    int d1 = dot(u, v);
    int d2 = dot(p, q);

    // Handle collinear cases (cross==0)
    if (c1 == 0 && c2 == 0) {
        if (d1 >= 0 && d2 >= 0) return d1 < d2; // both 0..180
        if (d1 < 0 && d2 >= 0) return false; // 180..360 > 0..180
        if (d1 >= 0 && d2 < 0) return true; // 0..180 < 180..360
        if (d1 < 0 && d2 < 0) return d1 > d2; // both >180, smaller angle = larger dot in negative
    }

    // Determine which quadrant the angle is in
    // Angle is "less" if it is in smaller CCW rotation (0..360)
    if (c1 >= 0 && c2 < 0) return true; // first in 0..180, second in 180..360
    if (c1 < 0 && c2 >= 0) return false; // first in 180..360, second in 0..180

    // Both in same half-plane: compare using cross/dot product
    // angle(u,v) < angle(p,q)  <=>  c1*d2 < c2*d1
    return (int)c1 * (int)d2 < (int)c2 * (int)d1;
}

Point reflect(const Point& p) {
    return Point(-p.x, -p.y);
}

Point normalize(const Point& middle, const Point& p) {
    return p - middle;
}

void solve() {
    int n;
    std::cin >> n;

    if (n <= 3) {
        return brut::solve(n);
    }

    points.resize(n);
    // workshop_points.resize(n - 1);
    // points.shrink_to_fit();

    for (int i = 0; i < n; i++) {
        int x, y;
        std::cin >> x >> y;

        // points[i] = {x, y, i};
        points[i] = {x, y, i};
    }

    int total = 0;

    // rozważ każdy punkt jako środek
    for (int i = 0; i < n; i++) {
        // i-ty punkt jako środek
        // do workshop_points daj wszysttkie punkty oprócz i-tego
        std::vector<Point> workshop_points;
        workshop_points.reserve(n - 1);
        for (int j = 0; j < n; ++j) {
            if (j == i) continue;
            workshop_points.push_back(normalize(points[i], points[j]));
        }
        int m = (int)workshop_points.size(); // m == n-1

        // posortuj kątowo względem tego punktu
        std::sort(workshop_points.begin(), workshop_points.end(), [](const Point& a, const Point& b) { return angle_less(a, b); });

        // przypisz odpowiednie zbiorki
        int num_L = 0, num_R = 0;
        Point sum_L(0, 0), sum_R(0, 0);
        int next_p_idx = -1, next_q_idx = -1;
        Point origin(0, 0);
        int idx = 0;
        for (const auto& p : workshop_points) {
            if (half_plane(p) == 1) {
                sum_L += p;
                num_L++;
                if (next_p_idx == -1) {
                    next_p_idx = idx;
                }
            } else {
                sum_R += p;
                num_R++;
                if (next_q_idx == -1) {
                    next_q_idx = idx;
                }
            }
            idx++;
        }

        // duplicate array so we can walk circularly
        workshop_points.resize(2 * m);
        for (int k = 0; k < m; ++k)
            workshop_points[m + k] = workshop_points[k];

        if (next_p_idx == -1) next_p_idx = next_q_idx;
        if (next_q_idx == -1) next_q_idx = next_p_idx;

        // i co teraz?
        // czas na zamiatanko!

        Point prev_p(1, 0), prev_q(-1, 0);

        int visited_num = 0;
        while (visited_num != n - 1) {
            if (angle_less2(prev_q, workshop_points[next_q_idx], prev_p, workshop_points[next_p_idx])) {
                // uderza półprosta `q`
                const auto& p = workshop_points[next_q_idx];
                sum_R -= p;
                sum_L += p;
                prev_p = reflect(p);
                prev_q = p;
                next_q_idx++;
            } else {
                // uderza półprosta `p`
                const auto& p = workshop_points[next_p_idx];
                total += _abs(cross(p, sum_L));
                total += _abs(cross(p, sum_R));
                sum_L -= p;
                sum_R += p;
                prev_q = reflect(p);
                prev_p = p;
                next_p_idx++;
                visited_num++;
            }
        }
    }

    int ans = total / 12;
    int ans1 = 0;
    if ((total / 6) & 1) ans1 = 5;

    std::cout << ans << "." << ans1 << std::endl;
}

int32_t main() {
#ifndef GARY_DBG
    std::ios_base::sync_with_stdio(0);
    std::cin.tie(0);
    std::cout.tie(0);
#endif

    int t = 1;
    // std::cin >> t;

    for (; t > 0; t--) {
        solve();
    }

    return 0;
}

namespace brut {
void solve(int n) {
    for (int i = 1; i <= n; i++) {
        int x, y;
        std::cin >> x >> y;

        points[i] = {x, y};
    }

    int total = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            for (int k = 1; k <= n; k++) {
                if (i == j || i == k || k == j) continue;
                int curr = llabs(points[i].first * (points[j].second - points[k].second) + points[j].first * (points[k].second - points[i].second) +
                                 points[k].first * (points[i].second - points[j].second));
                total += curr;
            }
        }
    }

    int ans = total / 12;
    int ans1 = 0;
    if ((total / 6) & 1) ans1 = 5;

    std::cout << ans << "." << ans1 << std::endl;
}
}