Probability of Constituting Triangle by HDU 4609 3-idiots

Keywords: PHP

http://acm.hdu.edu.cn/showproblem.php?pid=4609

The meaning of the question is to give you n line segments and ask you to choose three arbitrarily to form the probability of a triangle.

Firstly, the overall selection scheme is easy to obtain, and the direct combination number formula can be obtained.

Then it's about how triangles are made up.

For each length len[i], record a num array.

Then, by convoluting num and num, we can get the number of combinations of the lengths of two arbitrary line segments.

For example, 1334, his num array {0, 1, 0, 2, 1} convolution * {0, 1, 0, 2, 1}

It is obtained that {0,0,1,0,4,2,4,4,1} denotes the number of schemes of composition length. But we just need to be a triangle, so

We subtract the repeated selection and the number of identical segments selected twice.

Then we sort the line segments and traverse each line segment. As the third side, the two horizons we need to choose here are smaller than him, but they add up to be larger than him.

Therefore, the sum[tot]-sum[len[i] is the total number of solutions larger than num, which includes the selection of her own, as well as the large, small and two large cases.

Just subtract them separately. Just look at the code.

For the FFT part, the memory of the problem is very tight, so as to minimize the number of open arrays, while optimizing the constants as much as possible.

#include "bits/stdc++.h"

using namespace std;
const double eps = 1e-6;
#define reg register
#define lowbit(x) x&-x
#define pll pair<ll,ll>
#define pii pair<int,int>
#define fi first
#define se second
#define makp make_pair
#define cp complex<double>

int dcmp(double x) {
    if (fabs(x) < eps) return 0;
    return (x > 0) ? 1 : -1;
}

typedef long long ll;
typedef unsigned long long ull;
const ull hash1 = 201326611;
const ull hash2 = 50331653;
const ll N = 450000 + 10;
const int M = 1000000;
const int inf = 0x3f3f3f3f;
const ll mod = 1000000000 + 7;
const double Pi = acos(-1.0);

struct Complex {
    double x, y;

    Complex(double xx = 0, double yy = 0) { x = xx, y = yy; }
} a[N], omg[N];

Complex operator+(Complex a, Complex b) { return Complex(a.x + b.x, a.y + b.y); }

Complex operator-(Complex a, Complex b) { return Complex(a.x - b.x, a.y - b.y); }

Complex operator*(Complex a, Complex b) { return Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }

ll num[N], sum[N];
int len[N], r[N], lim, tot, n;

void init() {
    for (int i = 0; i < tot; i++) {
        omg[i] = Complex(cos(2 * Pi * i / tot), sin(2 * Pi * i / tot));
    }
    for (int i = 0; i < tot; i++) {
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (lim - 1));
    }
}

void fft(Complex *a, int inv) {
    for (int i = 0; i < tot; i++) {
        if (i < r[i]) swap(a[i], a[r[i]]);
    }
    for (int l = 2; l <= tot; l <<= 1) {
        int m = l / 2;
        for (Complex *p = a; p != a + tot; p += l) {
            for (int i = 0; i < m; i++) {
                Complex tt = omg[tot / l * i];
                ///Complex tt = Complex(cos(2 * Pi * i / l), sin(2 * Pi * i / l));
                if (inv) tt.y = -tt.y;
                Complex tmp = tt * p[i + m];
                p[i + m] = p[i] - tmp;
                p[i] = p[i] + tmp;
            }
        }
    }
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        memset(num, 0, sizeof(num));
        scanf("%d", &n);
        for (int i = 0; i < n; i++) {
            scanf("%d", &len[i]);
            num[len[i]]++;
        }
        sort(len, len + n);
        tot = 1, lim = 0;
        int n1 = len[n - 1] + 1;
        int n2 = 2 * n1 - 1;
        while (tot < n2 + 1) tot <<= 1, lim++;
        for (int i = 0; i < n1; i++)
            a[i] = Complex(num[i], 0);
        for (int i = n1; i < tot; i++)
            a[i] = Complex(0, 0);
        init();
        fft(a, 0);
        for (int i = 0; i < tot; i++) {
            a[i] = a[i] * a[i];
        }
        fft(a, 1);
        for (int i = 0; i < n2; i++) {
            num[i] = (ll) (a[i].x / tot + 0.5);
        }
        for (int i = 0; i < n; i++) num[2 * len[i]]--;
        for (int i = 0; i < n2; i++) num[i] /= 2;
        for (int i = 0; i < n2; i++) sum[i] = sum[i - 1] + num[i];
        ll cnt = 0;
        for (int i = 0; i < n; i++) {
            cnt += sum[n2 - 1] - sum[len[i]];
            cnt -= 1LL * (n - i - 1) * i;
            cnt -= (n - 1);
            cnt -= 1LL * (n - i - 1) * (n - i - 2) / 2;
        }
        ll vsum = 1LL * n * (n - 1) * (n - 2) / 6;
        printf("%.7f\n", 1.0 * cnt / vsum);
    }
    return 0;
}

 

Posted by knowNothing on Thu, 01 Aug 2019 23:32:32 -0700