HDU 4709 3-idiots FFT 多项式

http://acm.hdu.edu.cn/showproblem.php?pid=4609

给一堆边,求这一堆边随便挑三个能组成三角形的概率。

裸fft,被垃圾题解坑了还以为很难。

最长的边的长度小于其余两边之和是组成三角形的充要条件,fft搞搞就行了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #include<complex>
 7 using namespace std;
 8 #define LL long long
 9 const int maxn=530010;
10 double Pi;
11 typedef complex< double >cd;
12 cd b[maxn]={};
13 LL a[maxn]={},cnt[maxn]={};
14 int bel[maxn]={},s,bt;
15 void getit(){for(int i=0;i<s;++i)bel[i]=(bel[i>>1]>>1)|((i&1)<<(bt-1));}
16 void fft(cd *c,int n,int dft){
17     for(int i=0;i<n;++i)if(bel[i]>i)swap(c[i],c[bel[i]]);
18     for(int step=1;step<n;step<<=1){
19         cd w=cd(cos(Pi/(double)step),sin(Pi/(double)step)*(double)dft);
20         for(int j=0;j<n;j+=(step<<1)){
21             cd z=cd(1.0,0);
22             for(int i=j;i<j+step;++i){
23                 cd x=c[i],y=c[i+step]*z;
24                 c[i]=x+y;c[i+step]=x-y;
25                 z=z*w;
26             }
27         }
28     }
29     if(dft==-1)for(int i=0;i<n;++i)c[i]/=n;
30 }
31 int main(){
32     Pi=acos(-1.0);
33     int T;scanf("%d",&T);
34     while(T-->0){
35         int n;scanf("%d",&n);
36         memset(cnt,0,sizeof(cnt));
37         for(int i=0;i<n;++i){scanf("%d",&a[i]);cnt[a[i]]+=1;}
38         
39         sort(a,a+n); int siz=a[n-1]+1; 
40         for(int i=0;i<siz;++i)b[i]=cd(cnt[i],0);
41         for(int i=siz;i<s;++i)b[i]=cd(0,0);
42         
43         siz*=2; bt=1; s=2; for(;s<siz;++bt)s<<=1; getit();
44         fft(b,s,1);
45         for(int i=0;i<s;++i)b[i]=b[i]*b[i];
46         fft(b,s,-1);
47         for(int i=0;i<=s;++i)cnt[i]=(LL)(b[i].real()+0.5);
48         for(int i=0;i<s;++i)b[i]=cd(0,0);
49         
50         s=a[n-1]*2; 
51         for(int i=0;i<n;++i)--cnt[a[i]*2];
52         for(int i=1;i<=s;++i)cnt[i]/=2;
53         for(int i=1;i<=s;++i)cnt[i]+=cnt[i-1];
54         
55         LL ans=0;
56         for(int i=0;i<n;++i){
57             ans+=cnt[s]-cnt[a[i]];
58             ans-=(LL)(n-1-i)*i;
59             ans-=n-1;
60             ans-=(LL)(n-1-i)*(n-i-2)/2;
61         }
62         LL sum=(LL)n*(n-1)*(n-2)/6;
63         printf("%.7f\n",(double)(ans)/(double)(sum));
64     }
65     return 0;
66 }
View Code

 

posted @ 2018-06-12 18:30  鲸头鹳  阅读(85)  评论(0编辑  收藏  举报