【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
", sum);
        z += sum * (sum - 1) / 2;
        if (ed != i) sum --;
        else ed ++, sum = 0;
    }
    //printf("z: %I64d
", z);
    z = (LL)n * (n - 1) * (n - 2) / 6 - z;
    //printf("z: %I64d
", 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
", 1.0 * (2 * Q + P) / t + 3);
    return 0;
}
原文地址:https://www.cnblogs.com/tellmewtf/p/4572596.html