zoukankan      html  css  js  c++  java
  • HDU-4609 3-idiots

    Description

    King OMeGa catched three men who had been streaking in the street. Looking as idiots though, the three men insisted that it was a kind of performance art, and begged the king to free them. Out of hatred to the real idiots, the king wanted to check if they were lying. The three men were sent to the king's forest, and each of them was asked to pick a branch one after another. If the three branches they bring back can form a triangle, their math ability would save them. Otherwise, they would be sent into jail.
    However, the three men were exactly idiots, and what they would do is only to pick the branches randomly. Certainly, they couldn't pick the same branch - but the one with the same length as another is available. Given the lengths of all branches in the forest, determine the probability that they would be saved.

    Input

    An integer T(T≤100) will exist in the first line of input, indicating the number of test cases.
    Each test case begins with the number of branches (N(3≤N≤10 ^5)).
    The following line contains N integers (a_i (1≤a_i≤10 ^ 5)), which denotes the length of each branch, respectively.

    Output

    Output the probability that their branches can form a triangle, in accuracy of 7 decimal places.

    Sample Input

    2
    4
    1 3 3 4
    4
    2 3 3 4
    

    Sample Output

    0.5000000
    1.0000000
    

    题意

    从n根木棍取出三根,问组成三角形的概率有多大

    题解

    首先取出的全部方案即为(C_{n}^3),我们只需要算出合法的方案数,两数相除即为概率

    合法的方案考虑3种情况

    一是选择一根长度为c的,然后选择两根长度小于c,且和大于c的,长度小于c的木棍数(sum1)我们可以直接前缀和求,我们用fft可以求得两个木棍长度之和小于等于c的(sum2),然后(sum1*(sum1-1)/2-sum2)即为两根长度小于c的组成的和大于c的方案数,若长度为c的木棍共有(cnt[c])根,则此时方案数即为(cnt[c]*(sum1*(sum1-1)/2-sum2))

    二是选择两根长度为c的,方案数为(cnt[c]*(cnt[c]-1)/2),然后选择一根长度小于c的,方案数为(cnt[c]*(cnt[c]-1)/2*sum1)

    三是选择三根长度为c的,方案数为(C_{cnt[c]}^3)

    for一遍全都加起来即可

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const double pi = acos(-1.0);
    typedef long long ll;
    
    struct cp {
        double r, i;
        cp(double r = 0, double i = 0): r(r), i(i) {}
        cp operator + (const cp &b) {
            return cp(r + b.r, i + b.i);
        }
        cp operator - (const cp &b) {
            return cp(r - b.r, i - b.i);
        }
        cp operator * (const cp &b) {
            return cp(r * b.r - i * b.i, r * b.i + i * b.r);
        }
    };
    
    void change(cp a[], int len) {
        for (int i = 1, j = len / 2; i < len - 1; i++) {
            if (i < j) swap(a[i], a[j]);
            int k = len / 2;
            while (j >= k) {
                j -= k;
                k /= 2;
            }
            if (j < k) j += k;
        }
    }
    
    void fft(cp a[], int len, int op) {
        change(a, len);
        for (int h = 2; h <= len; h <<= 1) {
            cp wn(cos(-op * 2 * pi / h), sin(-op * 2 * pi / h));
            for (int j = 0; j < len; j += h) {
                cp w(1, 0);
                for (int k = j; k < j + h / 2; k++) {
                    cp u = a[k];
                    cp t = w * a[k + h / 2];
                    a[k] = u + t;
                    a[k + h / 2] = u - t;
                    w = w * wn;
                }
            }
        }
        if (op == -1) {
            for (int i = 0; i < len; i++) {
                a[i].r /= len;
            }
        }
    }
    const int N = 8e5 + 50;
    
    cp a[N];
    ll b[N];
    ll cnt[N];
    ll sum1[N];
    ll ans[N];
    ll sum2[N];
    int main() {
        int t; scanf("%d", &t);
        while (t--) {
            for (int i = 0; i <= 4e5; i++) {
                a[i] = cp(0, 0);
                b[i] = 0;
                cnt[i] = 0;
                sum1[i] = 0;
                sum2[i] = 0;
                ans[i] = 0;
            }
            int n;
            scanf("%d", &n);
            int len1 = 0;
            for (int i = 0; i < n; i++) {
                int x;
                scanf("%d", &x);
                len1 = max(len1, x + 1);
                cnt[x]++;
                a[x].r++;
                b[x + x]++;
            }
            int len = 1;
            while (len < 2 * len1) len <<= 1;
            fft(a, len, 1);
            for (int i = 0; i < len; i++) {
                a[i] = a[i] * a[i];
            }
            fft(a, len, -1);
            for (int i = 0; i < len; i++) {
                ans[i] = (ll)(a[i].r + 0.5);
                ans[i] -= b[i];
                ans[i] /= 2;
            }
    //        for (int i = 0; i < 10; i++) {
    //            printf("%d : %d
    ", i, ans[i]);
    //        }
            for (int i = 0; i < len; i++) {
                if (i) {
                    sum1[i] = sum1[i - 1] + cnt[i];
                    sum2[i] = sum2[i - 1] + ans[i];
                }
                else {
                    sum1[i] = cnt[i];
                    sum2[i] = ans[i];
                }
            }
            ll tot = (ll)n * (n - 1) * (n - 2) / 6;
            ll res = 0;
            for (int i = 1; i < len; i++) {
                if (cnt[i] >= 1) res += cnt[i] * (sum1[i - 1] * (sum1[i - 1] - 1) / 2 - sum2[i]);
                if (cnt[i] >= 2) res += cnt[i] * (cnt[i] - 1) / 2 * sum1[i - 1];
                if (cnt[i] >= 3) res += cnt[i] * (cnt[i] - 1) * (cnt[i] - 2) / 6;
            }
            //printf("%lld %lld
    ", res, tot);
            printf("%.7f
    ", (double)(res) / (double)tot);
        }
        return 0;
    }
    
  • 相关阅读:
    【php】 mac php-redis install
    【php】phpstorm 配置远程调试
    【cookie】cookie探讨
    第一篇文章
    SQL经典50查询语句案例_1(查询“001”课程比“002”课程成绩高的所有学生的学号)
    SQL经典50查询语句案例_10(查询没有学全所有课的同学的学号、姓名)
    SQL经典50查询语句案例_9(查询所有课程成绩小于60分的同学的学号、姓名)
    SQL经典50查询语句案例_8(查询课程编号“002”的成绩比课程编号“001”课程低的所有同学的学号、姓名)
    SQL经典50查询语句案例_7(查询学过“叶平”老师所教的所有课的同学的学号、姓名)
    SQL经典50查询语句案例_6(查询学过“001”并且也学过编号“002”课程的同学的学号、姓名)
  • 原文地址:https://www.cnblogs.com/artoriax/p/12187434.html
Copyright © 2011-2022 走看看