正难则反,首先概率就是\(\frac{合法的方案数}{总的方案数}\)=\(\frac{总的方案数-不合法的方案数}{总的方案数}\),统计不合法的方案数只需要 两个较短的边的长度和\(\le\)较长的边,用t[i]表示长度大于等于i的木棍的数量,f[i]为长度为i的木棍的数量,g[i]表示选出两根木棍组成和为i的方案数,很明显g等于f卷上f,注意自己不能卷自己,直接在最后让自己卷自己的方案数减去就行了。然后\(\displaystyle \sum \frac{g[i]}{2} \times t[i]\)就是不合法的方案数了。

bzoj数据比较毒瘤,NTT超时了,得用FFT才能过…

#include<bits/stdc++.h>
#define DB double
#define LL long long
#define AK 0
#define IOI ;
using namespace std;
int T,n,x,maxx,lim;
LL ans,tot;
const int N=400010;
const DB PI=acos(-1);
int r[N],t[N];
LL g[N];//f3?ê?·?°?  gá??ùD???1÷μ?·?°?  tò??ù′óóúμèóúiμ?·?°?
inline int read()
{
    int res = 0; char ch = getchar(); bool XX = false;
    for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
    for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
    return XX ? -res : res;
}
struct xu
{
    DB x,y;
    xu(DB X=0,DB Y=0){x=X,y=Y;}
    friend xu operator +(const xu &a,const xu &b)
    {return (xu){a.x+b.x,a.y+b.y};}
    friend xu operator -(const xu &a,const xu &b)
    {return (xu){a.x-b.x,a.y-b.y};}
    friend xu operator *(const xu &a,const xu &b)
    {return (xu){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};}
}f[N];
void FFT(xu *A,int lim,int opt)
{
    for(int i=0;i<lim;++i)
        r[i]=(r[i>>1]>>1)|((i&1)?(lim>>1):0);
    for(int i=0;i<lim;++i)
        if(i<r[i])swap(A[i],A[r[i]]);
    int len;
    xu wn,w,x,y;
    for(int mid=1;mid<lim;mid<<=1)
    {
        len=mid<<1;
        wn=(xu){cos(PI/mid),opt*sin(PI/mid)};
        for(int j=0;j<lim;j+=len)
        {
            w=(xu){1,0};
            for(int k=j;k<j+mid;++k,w=w*wn)
            {
                x=A[k];y=A[k+mid]*w;
                A[k]=x+y; A[k+mid]=x-y;
            }
        }
    }
}
void YYch()
{
    for(int i=0;i<=lim;++i)f[i]=g[i]=t[i]=0;
    maxx=0;lim=1;ans=tot=0;
}
inline void treAKer()
{
    YYch();
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        maxx=max(maxx,x=read());
        f[x].x++;t[x]++;g[x<<1]--;
    }
    for(int i=maxx;i>=1;--i)t[i]+=t[i+1];
    while(lim<=(maxx<<1))lim<<=1;
    FFT(f,lim,1);
    for(int i=0;i<lim;++i)f[i]=f[i]*f[i];
    FFT(f,lim,-1);
    for(int i=0;i<lim;++i)g[i]+=(int)(f[i].x/lim+0.5);
    tot=(LL)n*(n-1)*(n-2)/6;
    for(int i=0;i<lim;++i)ans+=(g[i]>>1)*t[i];
    printf("%.7f\n",(double)(tot-ans)/tot);
}
int main()
{
    cin>>T;
    while(T--)treAKer();
    return AK IOI;
}
02-10 17:08