题目链接: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 ", (double)ret/sum); 112 } 113 return 0; 114 }