[HDOJ4609]3-idiots(FFT,计数)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4609

题意:n个数,问取三个数可以构成三角形的组合数。

FFT预处理出两个数的组合情况,然后枚举第三个数,计数去重。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 const double PI = acos(-1.0);
  5 //复数结构体
  6 typedef struct Complex {
  7     double r,i;
  8     Complex(double _r = 0.0,double _i = 0.0) {
  9         r = _r; i = _i;
 10     }
 11     Complex operator +(const Complex &b) {
 12         return Complex(r+b.r,i+b.i);
 13     }
 14     Complex operator -(const Complex &b) {
 15         return Complex(r-b.r,i-b.i);
 16     }
 17     Complex operator *(const Complex &b) {
 18         return Complex(r*b.r-i*b.i,r*b.i+i*b.r);
 19     }
 20 }Complex;
 21 /*
 22  * 进行FFT和IFFT前的反转变换。
 23  * 位置i和 (i二进制反转后位置)互换
 24  * len必须是2的幂
 25  */
 26 void change(Complex y[],int len) {
 27     int i,j,k;
 28     for(i = 1, j = len/2;i < len-1; i++) {
 29         if(i < j)swap(y[i],y[j]);
 30         //交换互为小标反转的元素,i<j保证交换一次
 31         //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的
 32         k = len/2;
 33         while( j >= k) {
 34             j -= k;
 35             k /= 2;
 36         }
 37         if(j < k) j += k;
 38     }
 39 }
 40 /*
 41  * 做FFT
 42  * len必须为2^k形式,
 43  * on==1时是DFT,on==-1时是IDFT
 44  */
 45 void fft(Complex y[],int len,int on) {
 46     change(y,len);
 47     for(int h = 2; h <= len; h <<= 1) {
 48         Complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h));
 49         for(int j = 0;j < len;j+=h) {
 50             Complex w(1,0);
 51             for(int k = j;k < j+h/2;k++) {
 52                 Complex u = y[k];
 53                 Complex t = w*y[k+h/2];
 54                 y[k] = u+t;
 55                 y[k+h/2] = u-t;
 56                 w = w*wn;
 57             }
 58         }
 59     }
 60     if(on == -1) {
 61         for(int i = 0;i < len;i++) {
 62             y[i].r /= len;
 63         }
 64     }
 65 }
 66 
 67 typedef long long LL;
 68 const int maxn = 400300;
 69 Complex x1[maxn];
 70 int a[maxn/4];
 71 LL num[maxn], s[maxn];
 72 int n, len, q;
 73 
 74 int main() {
 75     // freopen("in", "r", stdin);
 76     int T;
 77     scanf("%d", &T);
 78     while(T--) {
 79         scanf("%d",&n);
 80         memset(a, 0, sizeof(a));
 81         memset(s, 0, sizeof(s));
 82         memset(num, 0, sizeof(num));
 83         int maxx = 0;
 84         for(int i = 0; i < n; i++) {
 85             scanf("%I64d", &a[i]);
 86             num[a[i]]++;
 87             maxx = max(maxx, a[i]);
 88         }
 89         int len1 = maxx + 1;
 90         len = 1;
 91         while(len < len1 * 2) len <<= 1;
 92         for(int i = 0; i < len; i++) x1[i] = Complex(0, 0);
 93         for(int i = 0; i < len1; i++) x1[i] = Complex(num[i], 0);
 94         fft(x1, len, 1);
 95         for(int i = 0; i < len; i++) x1[i] = x1[i] * x1[i];
 96         fft(x1, len, -1);
 97         for(int i = 0; i < len; i++) num[i] = (LL)(x1[i].r + 0.5);
 98         len = 2 * maxx;
 99         for(int i = 0; i < n; i++) num[a[i]*2]--; 
100         for(int i = 1; i <= len; i++) num[i] /= 2;
101         for(int i = 1; i <= len; i++) s[i] = s[i-1] + num[i];
102         LL ret = 0;
103         for(int i = 0; i < n; i++) {
104             ret += s[len] - s[a[i]];
105             ret -= (LL)(n - i - 1) * i;
106             ret -= (n - 1);
107             ret -= (LL)(n - i - 1) * (n - i - 2) / 2;
108         }
109         LL sum = (LL)n * (n - 1) * (n - 2) / 6;
110         // cout << (double)ret/(double)((n*(n-1)*(n-2))/6) << endl;
111         printf("%.7lf\n", (double)ret/sum);
112     }
113     return 0;
114 }

 

posted @ 2016-12-04 20:42  Kirai  阅读(182)  评论(0编辑  收藏  举报