统计每种长度的木棒数量,先计算出两根棒子能构成的长度,想到卷积。1.拿这个序列卷积自己 2.计算重算的部分,首先是一条边自己和自己的这种情况,另一种是(i,j)和(j,i)这种形式。第一种,可以枚举读入的木棒长度,再长度为其二倍的位置-1;第二种,在第一种处理完之后,直接除2。计算出两根棒子能构成的长度后,我们枚举最长的那条边,答案一定在长度大于它的里面,但是要去掉算了自己的情况,和存在一条边大于最长边的情况。具体公式看代码。这题中间精度差了些就挂了。可以用long long就不要用double。
#include <bits/stdc++.h> #define pi acos(-1.0) const int maxn = 300000+5; using namespace std; typedef long long ll; struct E{ double real,imag; E(double real=0,double imag=0):real(real),imag(imag){} friend E operator +(E A,E B){ return E(A.real+B.real,A.imag+B.imag); } friend E operator -(E A,E B){ return E(A.real-B.real,A.imag-B.imag); } friend E operator *(E A,E B){ return E(A.real*B.real-A.imag*B.imag,A.imag*B.real+A.real*B.imag); } }; int n,m,mx,L,rev[maxn]; E f[maxn],rf[maxn],g[maxn],e1[maxn],e2[maxn]; void fft(E *a,int ty,int n){ for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]); for(int i=1;i<n;i<<=1){ E wn=E(cos(pi/i),ty*sin(pi/i)); for(int p=(i<<1),j=0;j<n;j+=p){ E w(1,0); for(int k=0;k<i;++k,w=w*wn){ E x=a[j+k],y=w*a[j+k+i]; a[j+k]=x+y;a[j+k+i]=x-y; } } } if(ty==-1)for(int i=0;i<n;++i)a[i].real/=n; } E c[maxn]; int T; ll e[maxn],F[maxn],b[maxn]; int main() { scanf("%d",&T); while(T--) {ll mx = 0; scanf("%lld",&n); L=0; memset(c,0,sizeof(c)); memset(e,0,sizeof(e)); memset(rev,0,sizeof(rev)); memset(F,0,sizeof(F)); for(int i=1;i<=n;++i) { scanf("%lld",&e[i]); ++F[e[i]]; mx = max(mx,e[i]); } m = mx*2;for(mx=1;mx<=m;mx<<=1)++L; for(int i=0;i<mx;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1)); for(int i=0;i<mx;++i)c[i]=F[i]; fft(c,1,mx); for(int i=0;i<mx;++i) c[i]=c[i]*c[i]; fft(c,-1,mx); for(int i=0;i<mx;++i) b[i] = (ll)(c[i].real+0.5); for(int i=1;i<=n;++i) --b[e[i]<<1]; for(int i=0;i<mx;++i) b[i]>>=1; for(int i=1;i<mx;++i) b[i]+=b[i-1]; sort(e+1,e+1+n);ll ans = 0; for(int i=1;i<=n;++i){ ans = ans + (ll)(b[mx-1]-b[e[i]]); ans -= (ll)(n-1LL); ans -= (ll)(n-i)*(i-1); ans -= (ll)(n-i)*(n-i-1LL)/2LL; } ll t = 1LL*n*(n-1LL)*(n-2LL)/6LL; printf("%.7f\n",1.0*ans/t); } }