版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/89536247
【思路要点】
- 显然被选中的点受到的伤害总和为 ,考虑未被选中的点 对伤害总和的贡献。
- 首先,线段 必须与线段 相交,否则点 显然不存在贡献。
- 其次,若 ,那么 对答案的贡献为 ,若 ,那么 对答案的贡献为 。又由于四边形的内角和恰为 ,可以发现,有序组 与有序组 的贡献总和在线段 与线段 相交时为 ,否则为 。
- 因此,我们可以只计算满足线段 与线段 相交的有序组 的个数来计算贡献。
- 由于三点不共线,并且线段是一个凸集,相离的两条线段一定存在两条内公切线,枚举内公切线计算相离的线段数即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 2e5 + 5; typedef long long ll; typedef long double ld; typedef unsigned long long ull; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } struct point {__int128 x, y; } a[MAXN]; point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; } point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; } __int128 operator * (point a, point b) {return 1ll * a.x * b.y - 1ll * a.y * b.x; } bool quadrant(point a) { if (a.y == 0) return a.x >= 0; else return a.y >= 0; } bool cmp(point a, point b) { if (quadrant(a) == quadrant(b)) return a * b > 0; else return quadrant(a) < quadrant(b); } int main() { freopen("gbf.in", "r", stdin); freopen("gbf.out", "w", stdout); int n; read(n); for (int i = 1; i <= n; i++) read(a[i].x), read(a[i].y); ll ans = 4ll * n * (n - 1ll) * (n - 2ll) + n * (n - 1ll) * (n - 2ll) * (n - 3ll); for (int i = 1; i <= n; i++) { static point b[MAXN]; int tot = 0; for (int j = 1; j <= n; j++) if (i != j) b[++tot] = a[j] - a[i]; sort(b + 1, b + tot + 1, cmp); for (int j = 1, k = n; j <= n - 1; j++, k++) b[k] = b[j]; for (int j = 1, k = 1; j <= n - 1; j++, chkmax(k, j)) { while (b[j] * b[k + 1] > 0) k++; ans -= 4 * (k - j) * (n - 2 - (k - j)); } } writeln(ans); return 0; }