hdu4609 3-idiots

来源:互联网 发布:淘宝卖家电话采集 编辑:程序博客网 时间:2024/06/05 10:11

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.

先把原数组统计为出现次数数组,FFT求卷积得到两根树枝能拼成某长度的方案数。
对原数组排序之后枚举最长边,剩下两边要满足和大于当前边【在卷积中求前缀和查找】且都没有当前边大【因为已经排序,个数很好算】,用前者的总数减去后者的非法方案数。注意如果两条边相等,我们不妨认为右边的比左边的大,这样做到不重复计算。

#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>using namespace std;#define LL long longconst double pi=acos(-1.0);int rd(){    int x=0;    char c=getchar();    while (c<'0'||c>'9') c=getchar();    while (c>='0'&&c<='9')    {        x=x*10+c-'0';        c=getchar();    }    return x;}struct com{    double a,b;    com operator + (const com &c) const    {        return (com){a+c.a,b+c.b};    }    com operator - (const com &c) const    {        return (com){a-c.a,b-c.b};    }    com operator * (const com &c) const    {        return (com){a*c.a-b*c.b,a*c.b+b*c.a};    }}a[500010],b[500010],p[500010];int n,t,l,f[100010],r[500010];LL s[500010];int rev(int x){    int ret=0,i;    for (i=0;i<t;i++)        ret|=((x>>i)&1)<<t-i-1;    return ret;}void init(){    int i,m=0;    scanf("%d",&n);    memset(a,0,sizeof(a));    memset(b,0,sizeof(b));    for (i=1;i<=n;i++)        a[f[i]=rd()].a+=1,m=max(m,f[i]);    for (i=0;i<=m;i++)        b[i]=a[i];    m++;    m*=2;    l=1,t=0;    while (l<m) l<<=1,t++;    for (i=0;i<l;i++)        r[i]=rev(i);    p[0]=(com){1,0};    p[1]=(com){cos(2*pi/l),sin(2*pi/l)};    for (i=2;i<l;i++)    {        p[i]=p[i>>1]*p[i>>1];        if (i&1) p[i]=p[i]*p[1];    }}void fft(com *a,int c){    int i,j,k,w;    com u,v;    for (i=0;i<l;i++)        if (r[i]>i)            swap(a[i],a[r[i]]);    for (i=1;i<l;i<<=1)        for (j=0;j<l;j+=(i<<1))        {            w=0;            for (k=j;k<j+i;k++)            {                u=a[k];                v=a[k+i]*p[w];                a[k]=u+v;                a[k+i]=u-v;                w+=c*(l/i>>1);                if (w<0) w+=l;            }        }}double solve(){    int i;    LL ans=0;    fft(a,1);    fft(b,1);    for (i=0;i<l;i++)        a[i]=a[i]*b[i];    fft(a,-1);    for (i=0;i<l;i++)        a[i].a/=l;    for (i=1;i<=n;i++)        a[f[i]*2].a-=1;    for (i=0;i<l;i++)        a[i].a/=2;    s[0]=a[0].a+0.5;    for (i=1;i<l;i++)        s[i]=s[i-1]+a[i].a+0.5;     sort(f+1,f+n+1);    for (i=3;i<=n;i++)        ans+=s[l-1]-s[f[i]]-(n-1)-(LL)(n-i)*(i-1)-(LL)(n-i)*(n-i-1)/2;    return (double)ans/((LL)n*(n-1)*(n-2)/6);}int main(){    int T;    scanf("%d",&T);    while (T--)    {        init();        printf("%.7f\n",solve());    }}
0 0
原创粉丝点击