HDU 4609 3-idiots(FFT)

题意:给出n个正整数(数组A)。每次随机选出三个数。问这三个数能组成三角形的概率为多大?

首先,我们用类似桶排计数的方法作出两个数组a,b,储存每个长度有几条边,然后对两个数组求卷积。

求出卷积后,这就代表了2条边能构成的边长度的集合了,注意,由于求卷积的时候可能把两条相同的边相加,所以最后求出的数组一定要减去这重复的部分,然后,先算x后算y等价于先算y后算x,所以要除以二。

然后,对于第三条边a[i],我们这样考虑:令它作为这三条边中最大的那条!

所以之前的卷积求出来的两边和一定会比这条边大,所以每次都计数:ans+=sum[mx]-sum[a[i]];

然后减去重复部分:

    (1)一个选了i后面,一个选了i前面 (减去(i-1)*(n-i)个)

    (2)一个选了i,另一个随意 (减去n-1个)

    (3)两个都是i后面的 (减去C(n-i,2)个);

非常interesting的题目!

 1 #include<algorithm>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<complex>
 7 #define N 300005
 8 #define ll long long
 9 typedef std::complex<double> cd;
10 int a[400005];
11 ll C[400005],Sum[400005],A[400005],B[400005];
12 int n,mxnum;
13 int bitrev(int t,int n){
14     int res=0;
15     for (int i=0;i<n;i++) res|=((t>>(n-i-1))&1)<<i;//括号要多加 
16     return res;
17 }
18 void fft(cd *a,int n,int rev){
19     int len=1<<n;
20     static cd y[N];double Pi=acos(-1);
21     for (int i=0;i<len;i++) y[i]=a[bitrev(i,n)];
22     for (int d=1;d<len;d<<=1){
23         cd wn(exp(cd(0,Pi*rev/d)));
24         for (int k=0;k<len;k+=2*d){
25             cd w(1,0);
26             for (int i=k;i<k+d;i++,w*=wn){
27                 cd u=y[i],v=w*y[i+d];
28                 y[i]=u+v;
29                 y[i+d]=u-v;
30             }
31         }
32     }
33     if (rev==-1)
34     for (int i=0;i<len;i++) y[i]/=len;
35     for (int i=0;i<len;i++) a[i]=y[i];
36 }
37 void mul(ll *a,int la,ll *b,int lb,ll *c,int &lc){
38     int len=1,n=0;
39     static cd t1[N],t2[N];
40     for (;len<la*2||len<lb*2;len<<=1,n++);
41     for (int i=0;i<la;i++) t1[i]=cd(a[i],0);
42     for (int i=0;i<lb;i++) t2[i]=cd(b[i],0);
43     for (int i=la;i<len;i++) t1[i]=cd(0,0);
44     for (int i=lb;i<len;i++) t2[i]=cd(0,0);
45     fft(t1,n,1);fft(t2,n,1);
46     for (int i=0;i<len;i++) t1[i]*=t2[i];
47     fft(t1,n,-1);
48     for (int i=0;i<len;i++) c[i]=(long long)(t1[i].real()+0.5);
49     lc=len;
50 }
51 int main(){
52     int T;
53     scanf("%d",&T);
54     while (T--){
55         scanf("%d",&n);
56         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
57         mxnum=0;
58         for (int i=1;i<=n;i++) mxnum=std::max(mxnum,a[i]);
59         for (int i=1;i<=n;i++) A[a[i]]++,B[a[i]]++;
60         int lc;
61         mul(A,mxnum+1,B,mxnum+1,C,lc);
62         for (int i=1;i<=n;i++) C[a[i]*2]--;
63         for (int i=1;i<=mxnum*2;i++) C[i]/=2;
64         Sum[0]=0;
65         for (int i=1;i<=mxnum*2;i++) 
66          Sum[i]=Sum[i-1]+C[i];
67         std::sort(a+1,a+1+n);
68         ll ans=0;
69         for (int i=1;i<=n;i++){
70             ans+=Sum[mxnum*2]-Sum[a[i]];
71             ans-=(ll)n-1;
72             ans-=(ll)(i-1)*(n-i);
73             ans-=(ll)(n-i)*(n-i-1)/2;
74         }
75         ll sum=(ll)(n)*(n-1)*(n-2)/6;
76         printf("%.7f\n",(double)1.0*((double)(ans))/((double)sum));
77         for (int i=0;i<=mxnum;i++) A[i]=B[i]=Sum[i]=C[i]=0;
78     }
79 }

 

posted @ 2016-05-26 20:12  GFY  阅读(167)  评论(0编辑  收藏  举报