給定n條線段,隨機選3條,輸出三條線段能組成三角形的概率。
考慮暴力。枚舉兩條線段,第三條前綴和查詢。
在 時間內 枚舉兩條線段不太好辦。換種思路考慮。如果我們枚舉最長邊,去找2個短邊之和>最長邊的數量。
設 爲長度爲x的線段數量。
求 的卷積 。即爲兩條線段湊到一起長度爲x的組合的數量。
這樣會算重複線段本身還有每兩個不相同的線段多算2遍,減完除一下就好。
這樣我們可以得到兩條不相同的線段加起來值爲k的方案數。
枚舉最長邊。考慮如何計算合法答案。
一個三角形 我們枚舉了一條邊e,要求有2個不相同的邊相加長度>e。
有三種情況不合法:
1.兩條比他長的邊組成的方案。
2.一條比他長一條比他短的邊組成的方案。
3.他加上某條線段組成的方案。
減去即可計算出合法的方案數ans。
總方案數
最終概率爲
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double Pi=acos(-1);
const int MAXN=4e5+5;
struct cp{
double x,y;
cp(double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN],b[MAXN];
cp operator + (cp a,cp b){
return cp(a.x+b.x,a.y+b.y);
}
cp operator - (cp a,cp b){
return cp(a.x-b.x,a.y-b.y);
}
cp operator * (cp a,cp b){
return cp(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y);
}
int l,r[MAXN],limit=1,n,h[MAXN],maxn=0;
ll g[MAXN];
void FFT(cp*A,int ty){
for(int i=0;i<limit;i++){
if(i<r[i])swap(A[i],A[r[i]]);
}
for(int mid=1;mid<limit;mid<<=1){
int R=mid<<1;
cp Wn(cos(Pi/mid),ty*sin(Pi/mid));
for(int j=0;j<limit;j+=R){
cp W(1,0);
for(int k=0;k<mid;k++){
cp x=A[j+k],y=W*A[j+k+mid];
A[j+k]=x+y;
A[j+k+mid]=x-y;
W=W*Wn;
}
}
}
}
void rework(){
l=0;limit=1;maxn=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(r,0,sizeof(r));
memset(g,0,sizeof(g));
memset(h,0,sizeof(h));
}
void work(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&h[i]);
maxn=max(maxn,h[i]);
a[h[i]]=a[h[i]]+1;b[h[i]]=b[h[i]]+1;
}
maxn*=2;
while(limit<=maxn+2)l++,limit<<=1;
for(int i=0;i<limit;i++){
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
}
FFT(a,1);FFT(b,1);
for(int i=0;i<=limit;i++)a[i]=a[i]*b[i];
FFT(a,-1);
for(int i=0;i<=limit;i++)g[i]=ll(a[i].x/limit+0.5);
for(int i=1;i<=n;i++)g[h[i]<<1]--;
for(int i=0;i<=limit;i++)g[i]>>=1;
for(int i=1;i<=limit;i++)g[i]+=g[i-1];
sort(h+1,h+1+n);
ll ans=0;
for(int i=1;i<=n;i++){
// cout<<g[i]<<":"<<i<<endl;
ans+=g[limit]-g[h[i]];
ans-=1ll*(n-i)*(n-i-1)/2;//兩邊都>組成的g
ans-=1ll*(n-i)*(i-1);//一邊大於一邊小<組成的g
ans-=n-1;//他自己組成的g
}
//printf("%lld\n",ans);
printf("%.7lf\n",1.0*ans/((1ll*n*(n-1)*(n-2))/6));
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
rework();
work();
}
return 0;
}