版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/liufengwei1/article/details/86634455
辣鸡的我写一题看一题题解,计数是大弱项。。。总是想不清楚
求所有ai+aj方案数,进行fft,得到num[0...len]
去掉i=j的情况,所有num[a[i]*2]--;由于i,j顺序不考虑,所有num[i]/=2
然后对a数组排序,从1...到n枚举ai,把ai看做最大的边
(1)ans+=sum[len-1]-sum[a[i]],因为把ai看做最大边,那么要找有多少种2边之和大于ai
(2)ans-=n-1,他自己和其余n-1条边组合会大于他,所以减掉
(2)ans-=(i-1)*(n-i); 一条边比他小,一条比他大,和比ai大,有这么多种非法情况
(3)ans-=(n-i)(n-i-1)*2,两条都比他大,和比ai大,有这么多种非法情况
最后ans/c(n,3)就是概率了
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxl 100010
using namespace std;
const double pi=acos(-1.0);
long long n,mx;
int len;
long long a[maxl];
long long num[maxl*4],sum[maxl*4];
long long ans;
struct complex
{
double r,i;
complex(double r1=0.0,double i1=0.0)
{
r=r1;i=i1;
}
complex operator + (const complex &b)
{
return complex(r+b.r,i+b.i);
}
complex operator - (const complex &b)
{
return complex(r-b.r,i-b.i);
}
complex operator * (const complex &b)
{
return complex(r*b.r-i*b.i,r*b.i+i*b.r);
}
}x[maxl*4];
inline void prework()
{
scanf("%lld",&n);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
mx=a[n];
}
void change(complex y[],int len)
{
int i,j;
for(i=1,j=len/2;i<len-1;i++)
{
if(i<j)
swap(y[i],y[j]);
int k=len/2;
while(j>=k)
j-=k,k/=2;
if(j<k)
j+=k;
}
}
void fft(complex y[],int len,int on)
{
change(y,len);
for(int l=2;l<=len;l<<=1)
{
complex wn(cos(-on*2*pi/l),sin(-on*2*pi/l));
for(int j=0;j<len;j+=l)
{
complex w(1,0);
for(int k=j;k<j+l/2;k++)
{
complex u=y[k];
complex t=w*y[k+l/2];
y[k]=u+t;
y[k+l/2]=u-t;
w=w*wn;
}
}
}
if(on==-1)
for(int i=0;i<len;i++)
y[i].r/=len;
}
inline void mainwork()
{
len=1;
while(len<2*mx+1)
len<<=1;
for(int i=0;i<len;i++)
x[i]=complex(0.0,0.0);
for(int i=1;i<=n;i++)
x[a[i]].r++;
fft(x,len,1);
for(int i=0;i<len;i++)
x[i]=x[i]*x[i];
fft(x,len,-1);
for(int i=0;i<len;i++)
num[i]=(long long)(x[i].r+0.5);
for(int i=1;i<=n;i++)
num[a[i]*2]-=1;
for(int i=0;i<len;i++)
num[i]/=2;
for(int i=1;i<len;i++)
sum[i]=sum[i-1]+num[i];
ans=0;
for(int i=1;i<=n;i++)
{
ans+=sum[len-1]-sum[a[i]];
ans-=n-1;
ans-=(i-1)*(n-i);
ans-=(n-i)*(n-i-1)/2;
}
}
inline void print()
{
double ff=1.0*ans/(1.0*n*(n-1)*(n-2)/6);
printf("%.7f\n",ff);
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}