标签:col 组成 int sizeof bsp void def can swap
题意:给你一堆线段的长度,求任选三条能组成三角形的概率。
解法:先求出任选两条能组成的所有长度及其数量,这个过程可以用FFT实现。设a[i]代表长度为i的线段的数量,数组b为数组a的平方,然后从b中减去每条线段自己的贡献,即b[i*2]-=a[i],然后对所有的b[i]除以2,则b[i]就代表取两条线段长度和为i的方法数,剩下的用概率+前缀和搞一搞就行了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 typedef double db; 5 const int N=4e5+10; 6 const db pi=acos(-1); 7 struct P { 8 db x,y; 9 P operator+(const P& b) {return {x+b.x,y+b.y};} 10 P operator-(const P& b) {return {x-b.x,y-b.y};} 11 P operator*(const P& b) {return {x*b.x-y*b.y,x*b.y+y*b.x};} 12 P operator/(db b) {return {x/b,y/b};} 13 } p[N]; 14 void FFT(P* a,int n,int f) { 15 for(int i=1,j=n>>1,k; i<n-1; ++i,j^=k) { 16 if(i<j)swap(a[i],a[j]); 17 for(k=n>>1; j&k; j^=k,k>>=1); 18 } 19 for(int k=1; k<n; k<<=1) { 20 P wn= {cos(pi/k),f*sin(pi/k)}; 21 for(int i=0; i<n; i+=k<<1) { 22 P w= {1,0}; 23 for(int j=i; j<i+k; ++j,w=w*wn) { 24 P x=a[j],y=w*a[j+k]; 25 a[j]=x+y,a[j+k]=x-y; 26 } 27 } 28 } 29 if(!~f)for(int i=0; i<n; ++i)a[i]=a[i]/n; 30 } 31 int n,m,mx; 32 ll a[N],b[N]; 33 34 int main() { 35 int T; 36 for(scanf("%d",&T); T--;) { 37 ll ans=0; 38 memset(a,0,sizeof a),mx=0; 39 scanf("%d",&n); 40 for(int i=0; i<n; ++i) { 41 int x; 42 scanf("%d",&x); 43 a[x]++; 44 mx=max(mx,x); 45 } 46 memset(p,0,sizeof p); 47 for(m=1; m<=2*mx; m<<=1); 48 for(int i=0; i<m; ++i)p[i]= {a[i],0}; 49 FFT(p,m,1); 50 for(int i=0; i<m; ++i)p[i]=p[i]*p[i]; 51 FFT(p,m,-1); 52 for(int i=0; i<m; ++i)b[i]=p[i].x+0.5; 53 for(int i=0; i<m; ++i)b[i*2]-=a[i]; 54 for(int i=0; i<m; ++i)b[i]/=2; 55 for(int i=m-1; i>=0; --i)a[i]+=a[i+1]; 56 for(int i=0; i<m; ++i)ans+=a[i]*b[i]; 57 printf("%.7f\n",1-ans*1.0/n/(n-1)/(n-2)*6); 58 } 59 return 0; 60 }
标签:col 组成 int sizeof bsp void def can swap
原文地址:https://www.cnblogs.com/asdfsag/p/10502745.html