BZOJ3513
题目描述
题目大意:给定 n n n个长度分别为 a i a_i ai的木棒,问随机选择 3 3 3个木棒能够拼成三角形的概率。
题解
考虑用总的方案数-不合法的方案数,显然不合法即为两边之和小于第三边的情况
a
i
a_i
ai表示长度为
i
i
i的小木棍的数量,
g
i
g_i
gi表示长度大于等于
i
i
i的小木棍数量,
f
i
f_i
fi表示用2根小木棍拼成长度
为
i
i
i的方案数,则有
f
i
=
∑
j
+
k
=
i
a
i
a
k
f_i=\sum\limits_{j+k=i}a_ia_k
fi=j+k=i∑aiak
注意去重和选了同一条边的情况。
那么不合法的方案数即为
∑
f
i
g
i
\sum f_ig_i
∑figi
再计算出总的方案数
C
(
n
,
3
)
C(n,3)
C(n,3),最后计算概率即可
代码
#include <cmath>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int M=4e5+9;
const double pi=acos(-1.0);
int n,m,r[M],l,lim=1,num,ans,f[M],g[M],T;
struct complex{
double x,y;
complex(double xx=0,double yy=0){x=xx,y=yy;}
friend inline complex operator+(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
friend inline complex operator-(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
friend inline complex operator*(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
friend inline complex operator/(complex a,double b){return complex(a.x/b,a.y/b);}
friend inline complex operator*(complex a,double b){return complex(a.x*b,a.y*b);}
}a[M];
void FFT(complex *A,int type){
for(int i=0;i<lim;i++) if(i<r[i]) swap(A[i],A[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
complex W(cos(pi/mid),type*sin(pi/mid));
for(int R=mid<<1,j=0;j<lim;j+=R){
complex w(1,0);
for(int k=0;k<mid;k++,w=w*W){
complex x=A[j+k],y=w*A[j+k+mid];
A[j+k]=x+y;
A[j+mid+k]=x-y;
}
}
}
}
signed main(){
scanf("%lld",&T);
while(T--){
memset(a,0,sizeof(a));
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
memset(r,0,sizeof(r));
l=ans=num=m=0;
lim=1;
scanf("%lld",&n);
for(int i=1;i<=n;i++){
int x;scanf("%lld",&x);
a[x].x++;m=max(m,x);
f[x*2]--;
}for(int i=m;i>=1;i--) g[i]=g[i+1]+(long long)a[i].x;
while(lim<m*2) lim<<=1,l++;
for(int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
FFT(a,1);
for(int i=0;i<=lim;i++) a[i]=a[i]*a[i];
FFT(a,-1);
for(int i=0;i<=lim;i++){
f[i]+=(long long)(a[i].x/lim+0.5);
f[i]=f[i]/2;
}ans=num=n*(n-1)*(n-2)/6;
for(int i=0;i<=m;i++) ans-=f[i]*g[i];
//printf("%lld %lld\n",ans,num);
printf("%.7lf\n",(double)ans/(double)num);
}return 0;
}