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 }