Description
Input
输入第一行包含一个正整数 n n ,表示房子的总数。接下来有 行,分别表示 每一个房子的位置。对于 i=1,2,...,n i = 1 , 2 , . . . , n 第 i i 个房子的坐标用一对整数 和 yi y i 来表示,中间用空格隔开。
Output
输出文件包含一个实数,表示平均有多少个房子被信号所覆盖,需保证输出结果与精确值的绝对误差不超过 0.01 0.01 。
Sample Input
4
0 2
4 4
0 0
2 0
Sample Output
3.500
HINT
3.5,3.50,3.500,...
3.5
,
3.50
,
3.500
,
.
.
.
中的任何一个输出均为正确。此外,
3.49,3.51,
3.49
,
3.51
,
3.499999,…
3.499999
,
…
等也都是可被接受的输出。
【数据范围】
100% 的数据保证,对于
i=1,2,...,n
i
=
1
,
2
,
.
.
.
,
n
第
i
i
个房子的坐标 为整数
且
−1,000,000≤xi,yi≤1,000,000
−
1
,
000
,
000
≤
x
i
,
y
i
≤
1
,
000
,
000
。任何三个房子不在同一条直线上,任何四个房子不在同一个圆上。
40% 的数据,
n≤100
n
≤
100
。
70% 的数据,
n≤500
n
≤
500
。
100% 的数据,
3≤n≤1,500
3
≤
n
≤
1
,
500
。
Solution
对于四个点
A,B,C,D
A
,
B
,
C
,
D
,
如果点
D
D
在 内,那么:
△ABD
△
A
B
D
的外接圆不能覆盖点
C
C
;
的外接圆不能覆盖点
A
A
;
的外接圆不能覆盖点
B
B
;
的外接圆能覆盖点
D
D
。
除了构造外接圆使用的三个点之外,这样一组 的贡献为
1
1
。
否则四边形 是凸四边形。
画个图可以得出,除了构造外接圆使用的三个点之外,这种
ABCD
A
B
C
D
的贡献为
2
2
。
因此只需要统计出满足点 在
△ABC
△
A
B
C
内的
ABCD
A
B
C
D
的组数即可。
考虑一个一个枚举
D
D
,以 为极点,将剩下的
n−1
n
−
1
个点极角排序。
可这时候
△ABC
△
A
B
C
的个数还是不好直接统计,因此考虑补集转化,求以下这种情形的个数:
并用
C3n−1
C
n
−
1
3
减去上面的结果。
简单的说,就是求对于所有的
∠CDA<180°
∠
C
D
A
<
180
°
,点
A
A
和 之间(不包括点
A,C
A
,
C
)的点数之和。
考虑枚举
C
C
的同时,通过一个指针扫描,得出点 表示满足
∠CDA<180°
∠
C
D
A
<
180
°
并且
∠CDA
∠
C
D
A
最大的
A
A
。
这时候就可以得出固定点 和点
C
C
的方案个数了:只需要算出 和
C
C
之间(包括 而不包括
C
C
) 的点数 ,那么有
C2k
C
k
2
组
A,B
A
,
B
满足要求。
算上排序复杂度的话是
O(n2logn)
O
(
n
2
log
n
)
。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 3005;
int n, tot; ll ans, cnt;
struct cyx {
int x, y; double slo;
friend inline cyx operator - (const cyx &a, const cyx &b) {
return (cyx) {b.x - a.x, b.y - a.y};
}
friend inline ll operator * (const cyx &a, const cyx &b) {
return 1ll * a.x * b.y - 1ll * a.y * b.x;
}
} a[N], b[N];
inline bool comp(const cyx &x, const cyx &y) {return x.slo < y.slo;}
int pre(int i) {return i == 1 ? n - 1 : i - 1;}
int nxt(int i) {return i == n - 1 ? 1 : i + 1;}
int gap(int l, int r) {return l <= r ? r - l + 1 : n - l + r;}
int main() {
int i, j; n = read(); For (i, 1, n) a[i].x = read(), a[i].y = read();
ans = 1ll * n * (n - 1) * (n - 2) >> 1; For (i, 1, n) {
tot = 0; For (j, 1, n) if (j != i) b[++tot] = a[i] - a[j],
b[tot].slo = atan2(b[tot].y, b[tot].x); ll c0 = 0;
sort(b + 1, b + tot + 1, comp); int p = 1; For (j, 1, tot) {
while (b[j] * b[p] >= 0) {p = nxt(p); if (p == j) break;}
int w = gap(j, pre(p)) - 1; c0 += w * (w - 1) >> 1;
}
cnt += 1ll * (n - 1) * (n - 2) * (n - 3) / 6 - c0;
}
printf("%.6lf\n", 1.0 * (ans + cnt + (1ll * n * (n - 1) * (n - 2) * (n - 3)
/ 24 - cnt) * 2) / (1ll * n * (n - 1) * (n - 2) / 6)); return 0;
}