HDU 4609 3-idiots(FFT)
2015-09-01 20:59
351 查看
题意:给定n(n<=100000)个火柴棍的长度l(l<=100000),问任选三根能组成三角形的概率。
思路:这道题实际上就是问能组成多少三角形,如果直接枚举的话时间复杂度为O(n*n),无法承受。
注意到每根火柴棍的长度都小于等于10^5,所以可以把火柴棍的长度写成多项式的形式,
比如说现在有四根火柴棍长度为1,3,3,4,那么多项式的系数为{ 0, 1, 0, 2, 1},
表示长度为0的火柴有0个,长度为1的火柴有1个...,
那么我们可以把枚举两根火柴棍并计算相加后的长度这一步转化为两个多项式相乘,这一步可以用FFT加速,时间复杂度降为了O(n*logn),因为同一根火柴棍不能取两次而且取火柴棍没有次序问题,所以计算后要减去重复的。
于是我们就得到了任意两根火柴棍所能组成的长度,我们可以算出不能组成三角形的情况有多少种,然后一减得到答案。
对于求不能组成三角形的情况有多少种,我们可以先求出两根火柴能到达的长度的前缀和sum[v],即长度为1到v的方案有多少种,然后枚举所有火柴棍的长度,为了避免计算重复,我们认为当前枚举的的这根火柴棍是三角形中最长边,并记它的长度为v,那么一共有sum[v]种方案不合法,累加起来最后算出答案即可,注意精度问题和long long。
思路:这道题实际上就是问能组成多少三角形,如果直接枚举的话时间复杂度为O(n*n),无法承受。
注意到每根火柴棍的长度都小于等于10^5,所以可以把火柴棍的长度写成多项式的形式,
比如说现在有四根火柴棍长度为1,3,3,4,那么多项式的系数为{ 0, 1, 0, 2, 1},
表示长度为0的火柴有0个,长度为1的火柴有1个...,
那么我们可以把枚举两根火柴棍并计算相加后的长度这一步转化为两个多项式相乘,这一步可以用FFT加速,时间复杂度降为了O(n*logn),因为同一根火柴棍不能取两次而且取火柴棍没有次序问题,所以计算后要减去重复的。
于是我们就得到了任意两根火柴棍所能组成的长度,我们可以算出不能组成三角形的情况有多少种,然后一减得到答案。
对于求不能组成三角形的情况有多少种,我们可以先求出两根火柴能到达的长度的前缀和sum[v],即长度为1到v的方案有多少种,然后枚举所有火柴棍的长度,为了避免计算重复,我们认为当前枚举的的这根火柴棍是三角形中最长边,并记它的长度为v,那么一共有sum[v]种方案不合法,累加起来最后算出答案即可,注意精度问题和long long。
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack> #include<string> #include<map> #include<set> #include<ctime> #define eps 1e-6 #define LL long long #define pii (pair<int, int>) //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int maxn = 500000; //const int INF = 0x3f3f3f3f; const double PI = acos(-1.0); //复数结构体 struct complex { double r,i; complex(double _r = 0.0,double _i = 0.0) { r = _r; i = _i; } complex operator +(const complex &b) { return complex(r+b.r,i+b.i); } complex operator -(const complex &b) { return complex(r-b.r,i-b.i); } complex operator *(const complex &b) { return complex(r*b.r-i*b.i,r*b.i+i*b.r); } }; /* * 进行FFT和IFFT前的反转变换。 * 位置i和 (i二进制反转后位置)互换 * len必须取2的幂 */ void change(complex y[],int len) { int i,j,k; for(i = 1, j = len/2;i < len-1; i++) { if(i < j)swap(y[i],y[j]); //交换互为小标反转的元素,i<j保证交换一次 //i做正常的+1,j左反转类型的+1,始终保持i和j是反转的 k = len/2; while( j >= k) { j -= k; k /= 2; } if(j < k) j += k; } } /* * 做FFT * len必须为2^k形式, * on==1时是DFT,on==-1时是IDFT */ void fft(complex y[],int len,int on) { change(y,len); for(int h = 2; h <= len; h <<= 1) { complex wn(cos(-on*2*PI/h),sin(-on*2*PI/h)); for(int j = 0;j < len;j+=h) { complex w(1,0); for(int k = j;k < j+h/2;k++) { complex u = y[k]; complex t = w*y[k+h/2]; y[k] = u+t; y[k+h/2] = u-t; w = w*wn; } } } if(on == -1) for(int i = 0;i < len;i++) y[i].r /= len; } LL Sum[maxn], n, num[maxn], st[maxn]; complex stick[maxn]; int main() { //freopen("input.txt", "r", stdin); int T; cin >> T; while(T--) { memset(num, 0, sizeof(num)); memset(Sum, 0, sizeof(Sum)); cin >> n; int maxlen = 0, len = 1; for(int i = 0; i < n; i++) { int t; scanf("%d", &t); num[t]++; st[i] = t; maxlen = max(maxlen, t); } int tmp = (maxlen+1)<<1; while(len < tmp) len <<= 1; for(int i = 0; i <= maxlen; i++) stick[i] = complex((double)num[i], 0); for(int i = maxlen+1; i < len; i++) stick[i] = complex(0, 0); fft(stick, len, 1); for(int i = 0; i < len; i++) stick[i] = stick[i] * stick[i]; fft(stick, len, -1); for(int i = 0; i < n; i++) stick[st[i]*2].r -= 1; for(int i = 0; i < len; i++) stick[i].r /= 2; for(int i = 1; i < len; i++) Sum[i] = Sum[i-1] + (int)(stick[i].r+0.5); LL cant = 0; for(int i = 0; i < n; i++) cant += Sum[st[i]]; double ans = (double)((LL)n*(LL)(n-1)*(LL)(n-2)/6-(LL)cant) / (double)((LL)n*(LL)(n-1)*(LL)(n-2)/6); printf("%.7lf\n", ans); } return 0; }
相关文章推荐
- 智慧城市监控照明物联网管理系统应用分析
- 物联网云平台的建设将覆盖全领域
- 物联网方案分析的几个哲学命题
- 物联网支撑平台
- 物联网发展
- 智慧城市监控照明物联网管理系统应用分析
- 物联网云平台的建设将覆盖全领域
- 物联网:点燃JAVA未来之路的火炬
- 英特尔首推物联网云平台设备管理
- 英特尔首推物联网云平台设备管理
- 英特尔首推物联网云平台设备管理
- 物联网:点燃JAVA未来之路的火炬
- 物联网云平台介绍及应用模式
- 物联网软件工程 认识与问题
- 吴川斌博客--一个专注于物联网,智能硬件,可穿戴设备,智能家居,嵌入式系统,pcb设计,IT前沿科技的创客博客
- 物联网动了谁的奶酪?物联网物品的价值分析
- 物联网的核心究竟是什么?
- 物联网环境下的大吞吐量下消息服务集群设计
- 解析物联网三大实时协议
- 物联网架构分析之一:传输协议选择