题目大意

给定n条边的边值,求任意取三条边能组成三角形的概率

 

这里概率 P = valid/tot

tot = (n-2)*(n-1)*n/6是没问题的

valid表示合法的方式

先考虑,任意两条边组合形成方法的总数

因为边值在100000的范围内,这里组合用fft计算

得到最后形成和为 i 的两条边的方法数为 num[i]

这里计算后要记得减去取两条相同边的情况,还有 取 3,4 和 4,3是一样的,要记得除以2

最后跑个n的循环,每次将当前边作为排序后(主要是因为有长度相同的边才这么考虑)次序最大的边,然后保证得到的和是两条在它前面的边组成的

这个计算就需要求个总方法数的前缀和了

取到所有和大于当前边的方法数,减去由两条比它大的边组成的情况(n-i)*(n-i-1)/2,一个比他大一个比他小组成的(n-i)*(i-1),还有它其余任意一条边组成的(n-1)

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cmath>
  4 #include <iostream>
  5 #include <algorithm>
  6 using namespace std;
  7 #define N 100005
  8 #define ll long long
  9 const double PI = acos(-1.0);
 10 
 11 int n , a[N] , cnt[N] ;
 12 ll num[N<<2] , sum[N<<2];
 13 
 14 struct complex{
 15     double r , i;
 16     complex(double r=0 , double i=0):r(r),i(i){}
 17     complex operator+(const complex &a) const{
 18         return complex(r+a.r , i+a.i);
 19     }
 20     complex operator-(const complex &a) const{
 21         return complex(r-a.r , i-a.i);
 22     }
 23     complex operator*(const complex &a) const{
 24         return complex(r*a.r-i*a.i , r*a.i+i*a.r);
 25     }
 26 };
 27 
 28 void change(complex y[] , int len)
 29 {
 30     int i,j,k;
 31     for(i=1 , j=len/2 ; i<len-1 ; i++){
 32         if(i<j) swap(y[i],y[j]);
 33         k = len/2;
 34         while(j>=k){
 35             j-=k;
 36             k/=2;
 37         }
 38         if(j<k) j+=k;
 39     }
 40 }
 41 
 42 void fft(complex y[] , int len , int on)
 43 {
 44     change(y , len);
 45     for(int i=2 ; i<=len ; i<<=1){
 46         complex wn(cos(-on*2*PI/i) , sin(-on*2*PI/i));
 47         for(int j=0 ; j<len ; j+=i){
 48             complex w(1,0);
 49             for(int k=j ; k<j+i/2 ; k++){
 50                 complex u = y[k];
 51                 complex t = w*y[k+i/2];
 52                 y[k] = u+t;
 53                 y[k+i/2] = u-t;
 54                 w = w*wn;
 55             }
 56         }
 57     }
 58     if(on==-1)
 59         for(int i=0 ; i<len ; i++)
 60             y[i].r /= len;
 61 
 62 }
 63 complex x[N<<2];
 64 
 65 int main()
 66 {
 67    // freopen("a.in" , "r" , stdin);
 68     int T;
 69     scanf("%d" , &T);
 70     while(T--){
 71         scanf("%d" , &n);
 72         int mx = 0;
 73         memset(cnt , 0 , sizeof(cnt));
 74         for(int i=1 ; i<=n ; i++){
 75             scanf("%d" , &a[i]);
 76             cnt[a[i]]++ , mx=max(mx , a[i]);
 77         }
 78         int len = 1;
 79         while(len<2*(mx+1)) len<<=1;
 80         for(int i=0 ; i<=mx ; i++) x[i] = complex(cnt[i] , 0);
 81         for(int i=mx+1 ; i<len ; i++) x[i] = complex(0 , 0);
 82         fft(x , len , 1);
 83         for(int i=0 ; i<len ; i++)
 84             x[i] = x[i]*x[i];
 85         fft(x , len , -1);
 86         for(int i=0 ; i<len ; i++) num[i] = (ll)(x[i].r+0.5);
 87         for(int i=1 ; i<=n ; i++) num[a[i]+a[i]]--;
 88         for(int i=0 ; i<len ; i++){
 89             num[i]/=2;
 90             if(i) sum[i] = sum[i-1]+num[i];
 91         }
 92         ll ans = 0;
 93         sort(a+1 , a+n+1);
 94         for(int i=1 ; i<=n ; i++){
 95             ll val = sum[len-1]-sum[a[i]];
 96             val = val - (n-1);
 97             val = val - (ll)(n-i)*(i-1);
 98             val = val - (ll)(n-i)*(n-i-1)/2;
 99           //  cout<<i<<" "<<a[i]<<" "<<sum[len-1]-sum[a[i]]<<" "<<val<<endl;
100             ans = ans+val;
101         }
102         printf("%.7f\n" , ans*6.0/((ll)n*(n-1)*(n-2)));
103     }
104     return 0;
105 }

 

 posted on 2015-10-26 12:28  Love风吟  阅读(190)  评论(0编辑  收藏  举报