【BZOJ1913】[Apio2010]signaling 信号覆盖
题意:一个平面上n个点,随机选3个点构成一个圆,问期望有多少个点在这个圆内。数据保证没有4点共圆、3点共线和重点。
认为比较难想到
因为是等概率选择,所以只要求所有情况包含的点总数
在所有C(n, 3)种情况中,每个被圆包含的点都可以对应到一个四边形上
因此求出凸四边形和凹四边形的个数就可以算出答案
1.对于凸四边形有两种方法可以包含4个点
2.对于凹四边形只有一种方法可以包含4个点
ans = (2 * Q + P) / C(n, 3) + 3
#include <cstdio> #include <cmath> #include <iostream> #include <algorithm> using namespace std; #define V P const double eps = 1e-9; inline int dcmp (const double& x) { return x < -eps ? -1 : x > eps; } struct P { double x, y; void scan() { scanf("%lf%lf", &x, &y); } P(double x = 0, double y = 0) : x(x), y(y) { } V operator + (const V& a) const { return V(x + a.x, y + a.y); } V operator - (const V& a) const { return V(x - a.x, y - a.y); } V operator * (const double& p) const { return V(p * x, p * y); } V operator / (const double& p) const { return V(x / p, y / p); } bool operator < (const P& a) const { return x < a.x || (dcmp(x - a.x) == 0 && y < a.y); } bool operator == (const P& a) const { return dcmp(x - a.x) == 0 && dcmp(y - a.y) == 0; } }; inline double dot(const V& a, const V& b) { return a.x * b.x + a.y * b.y; } inline double len(const V& a) { return sqrt(dot(a, a)); } inline double dis(const P& a, const P& b) { return len(b - a); } inline double ang(const V& a, const V& b) { return acos(dot(a, b) / len(a) / len(b)); } inline double cross(const V& a, const V& b) { return a.x * b.y - a.y * b.x; } inline int get(const P& a) { if( a.x > 0 && a.y >= 0) return 1; if( a.x <= 0 && a.y > 0) return 2; if( a.x < 0 && a.y <= 0) return 3; if( a.x >= 0 && a.y < 0) return 4; return 0; } inline bool cmp (const V& a, const V& b) { return get(a) < get(b) || (get(a) == get(b) && dcmp( cross(a, b) ) >0); } const int N = 2100; P p[N], b[N]; int n; typedef long long LL; LL res[N]; LL solve(int n, P* p) { for (int i = 1; i <= n; i ++) p[i] = p[i] - p[0]; sort(p + 1, p + 1 + n, cmp); for (int i = 1; i <= n; i ++) p[i - 1] = p[i]; int ed = 0, sum = 0; LL z = 0; for (int i = 0; i < n; i ++) { while(dcmp(cross(p[i], p[(ed + 1) % n])) == 1) ed = (ed + 1) % n, sum ++; //printf("%d\n", sum); z += sum * (sum - 1) / 2; if (ed != i) sum --; else ed ++, sum = 0; } //printf("z: %I64d\n", z); z = (LL)n * (n - 1) * (n - 2) / 6 - z; //printf("z: %I64d\n", z); return z; } LL t; int main() { freopen("a.in", "r", stdin); scanf("%d", &n); for (int i = 1; i <= n; i ++) p[i].scan(); LL P = 0, Q = 0; for (int i = 1; i <= n; i ++) { int cnt = 0; for (int j = 1; j <= n; j ++) if (j != i) b[++ cnt] = p[j]; b[0] = p[i]; P += solve(n - 1, b); } Q = (LL)n * (n - 1) * (n - 2) * (n - 3) / 24 - P; t = (LL)n * (n - 1) * (n - 2) / 6; printf("%.6lf\n", 1.0 * (2 * Q + P) / t + 3); return 0; }