hdu 4609 3-idiots [FFT计数]【数学】

68 篇文章 0 订阅

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4609
———————————————————–.
3-idiots

Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4437 Accepted Submission(s): 1561

Problem 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≤105).
The following line contains N integers a_i (1≤a_i≤105), 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

Source
2013 Multi-University Training Contest 1
———————————————————–.
题目大意:
就是跟你N个数代表长度为 ai 的木棒,现在问你随便拿出来三个就能构成三角形的概率为多少

解题思路:
首先考虑暴力的
就是求 aiaj<k<ai+aj 满足题意的这样的值有多少个,那么这样的话,我们就需要知道,这N个数两两加的和是什么样的,计算出这个之后,我们在预处理出前缀和之后就可以通过枚举最长边来 O(n) 计算三角形的情况数,再除以 C3n=n(n1)(n2)6 就是概率了,

所以最严重的问题就是如何求这N个数的两两相加.
这时候如果把加法换成乘法那么就可以转化为向量相乘,用FFT就可以 o(nlog2n) 解决了

然后我们考虑将加法换成乘法,其实很简单,我们只要将加数代换成幂指数的指数就可以了,
anam=an+m

我们可以用一个hash[a[i]]来记录每个大小的数都有几个
那么FFT之后的结果稍加一点简单处理就是两个不同的木棍长度加和wei [i] 的情况数

而我们要的就是这个情况数,所以就不需要在继续处理了

附本题链接
———————————————————–.

#include <bits/stdc++.h>

using namespace std;

#define INF        (~(1<<31))
#define INFLL      (~(1ll<<63))
#define pb         push_back
#define mp         make_pair
#define abs(a)     ((a)>0?(a):-(a))
#define lalal      puts("*******");
#define s1(x)      scanf("%d",&x)
#define Rep(a,b,c) for(int a=(b);a<=(c);a++)
#define Per(a,b,c) for(int a=(b);a>=(c);a--)
#define no         puts("NO")

typedef long long int LL ;
typedef unsigned long long int uLL ;

const int    MOD = 1e9+7;
const int    N   = 264000+5;
const double eps = 1e-6;
const double PI  = acos(-1.0);
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void fre(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
}

/***********************************************************************/
struct Complex{
    double real, image;
    Complex(double _real, double _image){
        real = _real;
        image = _image;
    }
    Complex(){}

    Complex operator + (const Complex &tmp){
        return Complex(real + tmp.real, image + tmp.image);
    }
    Complex operator - (const Complex &tmp){
        return Complex(real - tmp.real, image - tmp.image);
    }
    Complex operator * (const Complex &tmp){
        return Complex(real*tmp.real - image*tmp.image, real*tmp.image + image*tmp.real);
    }
};
int rev(int id, int len){
    int ret = 0;
    for(int i = 0; (1 << i) < len; i++){
        ret <<= 1;
        if(id & (1 << i)) ret |= 1;
    }
    return ret;
}
Complex A[264000];
void FFT(Complex *a, int len, int DFT){
    for(int i = 0; i < len; i++)
        A[rev(i, len)] = a[i];
    for(int s = 1; (1 << s) <= len; s++){
        int m = (1 << s);
        Complex wm = Complex(cos(DFT*2*PI/m), sin(DFT*2*PI/m));
        for(int k = 0; k < len; k += m){
            Complex w = Complex(1, 0);
            for(int j = 0; j < (m >> 1); j++){
                Complex t = w*A[k + j + (m >> 1)];
                Complex u = A[k + j];
                A[k + j] = u + t;
                A[k + j + (m >> 1)] = u - t;
                w = w*wm;
            }
        }
    }
    if(DFT == -1) for(int i = 0; i < len; i++) A[i].real /= len, A[i].image /= len;
    for(int i = 0; i < len; i++) a[i] = A[i];
    return;
}


int num[100010],h[200010];
Complex a[264000];
LL tA[200010],sum[200010];

int main()
{
    int _, n;
    while(~scanf("%d", &_))
    while(_--)
    {
        scanf("%d", &n);
        int mx = 0;
        memset(h, 0, sizeof(h));
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &num[i]);
            h[num[i]]++;
        }
        sort(num+1, num + n+1);
        mx = num[n];

        int len = 1;
        while(len <= mx) len <<= 1;  len <<= 1;
        for(int i = 0; i < len; i++)  a[i] = Complex((i<=mx)?h[i]:0, 0);

        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 <= (mx<<1); i++)   tA[i] = (LL)(a[i].real + 0.5);

        for(int i=0;i<=n;i++) tA[num[i]<<1]--;
        for(int i = 0; i <= (mx<<1); i++)  tA[i] >>=1;
        //到现在为止A[i]表示的是去两根不同的branch的长度和为i的组合种数
        sum[0] = 0;
        for(int i = 1; i <= (mx<<1); i++)  sum[i] = sum[i - 1] + tA[i];
        LL ans = 0;

        for(int i = 1; i <= n; i++)//以第i根作为边最长的
        {
            LL tmp = sum[(mx<<1)] - sum[num[i]];//另外两条边长度和要大于branch[i]
            tmp -= (LL)(n - i)*(i - 1);//另外两条一条比branch[i]长, 一条不比它长
            tmp -= (LL)(n - i)*(n - i - 1) / 2;//两条都比他长
            tmp -= n - 1;//另外两条的组合中包括它自己的组合
            ans += tmp;
        }
        printf("%.7f\n",ans*6./n/(n - 1)/(n - 2));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值