連接ios
首先想 \(O(n^3)\) 的暴力,不難發現枚舉 \(A\) 和 \(D\) 後, \((B,C)\) 和 \((E,F)\) 兩組點互相之間沒有影響,所以能夠分開計算,對於任意一組點,枚舉其中一個點,另外一個點即爲枚舉的點關於 \(AD\) 的對稱點,暴力統計便可spa
而後首先考慮 \((E,F)\) 一組點。因爲有 \(\angle ADE, \angle ADF \gt 90 \degree\) 的限制,那麼 \(E,F\) 兩個點被限制在一個半平面內。考慮先枚舉 \(D\) 再按照極角序枚舉 \(A\),那麼每一個點進入可用半平面一次離開可用半平面一次,複雜度 \(O(n^2)\)code
下面考慮 \((B, C)\) 一組點。若是 \(A,D\) 肯定了,那麼至關於肯定了 \(BC\) 的斜率。能夠預處理枚舉全部的 \(B,C\) 並按斜率歸類,而且因爲每一組 \(B,C\) 的斜率都相同,那麼其所能對應的 \(AD\) 的斜率也相同,又 \(BC\) 的中點在 \(AD\) 上,因此對於肯定的 \(BC\) 能夠肯定出 \(AD\) 所在直線。按照所在直線歸類,每一類中按照 \(BC\) 的中點的 \(x\) 座標排序,那麼當 \(AD\) 肯定時,僅需在其對應的一類中查詢中點座標在 \(AD\) 之間的全部 \(B,C\) 並統計個數,能夠二分出結果,複雜度 \(O(n^2\log n^2)\)排序
// Copyright lzt #include <stdio.h> #include <cstring> #include <cstdlib> #include <algorithm> #include <vector> #include <map> #include <set> #include <cmath> #include <iostream> #include <queue> #include <string> #include <ctime> using namespace std; typedef long long ll; typedef pair<int, int> pii; typedef long double ld; typedef unsigned long long ull; typedef pair<long long, long long> pll; #define fi first #define se second #define pb push_back #define mp make_pair #define rep(i, j, k) for (register int i = (int)(j); i <= (int)(k); i++) #define rrep(i, j, k) for (register int i = (int)(j); i >= (int)(k); i--) #define Debug(...) fprintf(stderr, __VA_ARGS__) inline ll read() { ll x = 0, f = 1; char ch = getchar(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); } while (ch <= '9' && ch >= '0') { x = 10 * x + ch - '0'; ch = getchar(); } return x * f; } struct P { long long x, y; long long len() { return 1ll * x * x + 1ll * y * y; } } a[1009]; long long ans; vector<int> p[1009][1009], v[1009][1009]; long long n, id[1009], nw, cnt[1009][1009][2], CNT, po, PO, tot, val[1000061], ID[1000061]; P dir[1000061]; bool bo[1009]; int nxt(int x) { return x == n ? 2 : x + 1; } long long operator^(P a, P b) { return 1ll * a.x * b.y - 1ll * a.y * b.x; } P operator-(P a, P b) { return (P){a.x - b.x, a.y - b.y}; } P operator*(P a, int b) { return (P){a.x * b, a.y * b}; } bool cmp(int x, int y) { return (a[x] - a[nw]).len() < (a[y] - a[nw]).len(); } bool check(int x) { return a[x].x > a[nw].x || a[x].x == a[nw].x && a[nw].y < a[x].y; } bool CHECK(int x) { return dir[x].x > a[nw].x || dir[x].x == a[nw].x && a[nw].y < dir[x].y; } bool Check(P x) { return x.x > a[nw].x || x.x == a[nw].x && a[nw].y < x.y; } bool Check2(P x) { return x.x > a[nw].x || x.x == a[nw].x && a[nw].y > x.y; } bool CMP(int x, int y) { if (check(x) ^ check(y)) return check(x); return ((a[x] - a[nw]) ^ (a[y] - a[nw])) < 0; } bool PMC(int x, int y) { if (CHECK(x) ^ CHECK(y)) return CHECK(x); return ((dir[x] - a[nw]) ^ (dir[y] - a[nw])) < 0; } bool Cmp(P x, P y) { if (Check(x) ^ Check(y)) return Check(x); return ((x - a[nw]) ^ (y - a[nw])) <= 0; } bool Cmp2(P x, P y) { if (Check2(x) ^ Check2(y)) return Check2(x); return ((x - a[nw]) ^ (y - a[nw])) < 0; } void ins(int j) { if (bo[j]) return; bo[j] = 1; for (int k = 0, sz = v[nw][j].size(); k < sz; k++) if (bo[v[nw][j][k]]) CNT++; } void del(int j) { if (!bo[j]) return; bo[j] = 0; for (int k = 0, sz = v[nw][j].size(); k < sz; k++) if (bo[v[nw][j][k]]) CNT--; } int main() { scanf("%lld", &n), ans = 0; for (int i = 1; i <= n; i++) scanf("%lld%lld", &a[i].x, &a[i].y); for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) id[j] = j; nw = i, sort(id + 1, id + 1 + n, cmp); for (int j = 2; j <= n; j++) for (int k = j - 1; (a[id[j]] - a[nw]).len() == (a[id[k]] - a[nw]).len(); k--) if (((a[id[j]] - a[nw]) ^ (a[id[k]] - a[nw])) != 0) { tot = 0; if (id[j] > id[k]) swap(j, k), tot = 1; p[id[j]][id[k]].push_back(i), v[i][id[j]].push_back(id[k]), v[i][id[k]].push_back(id[j]); if (tot) swap(j, k); } } for (int i = 1; i <= n; i++) for (int j = i + 1; j <= n; j++) { cnt[i][j][0] = cnt[i][j][1] = 0; for (int k = 0, sz = p[i][j].size(); k < sz; k++) if (((a[i] - a[j]) ^ (a[i] - a[p[i][j][k]])) > 0) cnt[i][j][0]++; else cnt[i][j][1]++; } for (int i = 1; i <= n; i++) { n += 8; memset(bo, 0, sizeof(bo)), tot = 1; for (int j = 1; j <= n - 8; j++) if (i != j) id[++tot] = j; a[id[++tot] = (n - 7)] = (P){a[i].x + 1, a[i].y}; a[id[++tot] = (n - 6)] = (P){a[i].x, a[i].y - 1}; a[id[++tot] = (n - 5)] = (P){a[i].x - 1, a[i].y}; a[id[++tot] = (n - 4)] = (P){a[i].x, a[i].y + 1}; a[id[++tot] = (n - 3)] = (P){a[i].x + 1, a[i].y + 1}; a[id[++tot] = (n - 2)] = (P){a[i].x + 1, a[i].y - 1}; a[id[++tot] = (n - 1)] = (P){a[i].x - 1, a[i].y - 1}; a[id[++tot] = n] = (P){a[i].x - 1, a[i].y + 1}; nw = i, sort(id + 2, id + 1 + n, CMP), CNT = 0, po = n; for (int j = 2; j <= n; j++) if (a[id[j]].x > a[i].x) ins(id[po = j]); PO = 2, tot = 0; rep(j, 1, n) rep(k, 1, n) { if (j == k) continue; } rep(j, 1, n) rep(k, 1, n) { if (j == k) continue; } rep(j, 1, n) rep(k, 1, n) { if (j == k) continue; } for (int j = 1; j <= n; j++) for (int k = 0, sz = v[i][j].size(), X; k < sz; k++) if (v[i][j][k] > j) { X = v[i][j][k]; dir[++tot] = (P){a[j].x + a[X].x - a[i].x - a[i].x, a[j].y + a[X].y - a[i].y - a[i].y}; dir[tot] = (P){a[i].x + dir[tot].y, a[i].y - dir[tot].x}; if (((a[j] - a[X]) ^ (a[j] - a[i])) > 0) val[tot] = cnt[j][X][1]; else val[tot] = cnt[j][X][0]; } dir[++tot] = (P){a[i].x, a[i].y + 1}, val[tot] = 0; dir[++tot] = (P){a[i].x + 1, a[i].y}, val[tot] = 0; dir[++tot] = (P){a[i].x, a[i].y - 1}, val[tot] = 0; dir[++tot] = (P){a[i].x - 1, a[i].y}, val[tot] = 0; dir[++tot] = (P){a[i].x + 1, a[i].y + 1}, val[tot] = 0; dir[++tot] = (P){a[i].x + 1, a[i].y - 1}, val[tot] = 0; dir[++tot] = (P){a[i].x - 1, a[i].y - 1}, val[tot] = 0; dir[++tot] = (P){a[i].x - 1, a[i].y + 1}, val[tot] = 0; for (int j = 1; j <= tot; j++) ID[j] = j; sort(ID + 1, ID + 1 + tot, PMC); int en = nxt(po); bool BO = 0; for (int j = 2; j <= n; j++) if (!check(id[j]) || a[id[j]].x > a[i].x) { PO = j; break; } for (int j = 1; j <= tot; j++) { while ((!BO || nxt(po) != en) && Cmp2((P){a[i].x * 2 - dir[ID[j]].x, dir[ID[j]].y}, (P){a[id[nxt(po)]].x, a[i].y * 2 - a[id[nxt(po)]].y})) BO = 1, ins(id[po = nxt(po)]); while (PO <= n && Cmp(a[id[PO]], dir[ID[j]])) del(id[PO]), PO++; ans += 1ll * CNT * val[ID[j]]; } n -= 8; } printf("%lld\n", ans * 4ll); return 0; }