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

题意: 给定 N 个正整数, 表示 N 条线段的长度, 问任取 3 条, 可以构成三角形的概率为多少~

数据范围: N<=10^5 ~~

思路:设三边分别为 x, y, z (x<=y<=z) 枚举 z ,统计 x+y 大于 z 的数目 .

比赛时能想到的只有 O(n^2) 的算法,无力 AC~

赛后才知道有种东西叫 FFT ~

以下为官方解题报告:

/*

  记录 A_i 为长度为 i 的树枝的数量,并让 A 对它本身做 FFT,得到任意选两个树枝能得到的各个和的数量。枚举第三边,

计算出所有两边之和大于第三条边的方案数,并把前两条边包含最长边的情况减掉就是答案。

*/

设长度为 a1,a2, ....an, 统计每种长度个数为 cnt[ ai ] ; 可表示多项式      

多项式自乘后, 其指数即为 ai + aj 的值, 系数即为 方案数, 减去不合法的即为所求~

  1. #include <cstdio>
  2. #include <cmath>
  3. #include <iostream>
  4. #include <algorithm>
  5. #include <cstring>
  6. using namespace std;
  7. typedef __int64 LL;
  8. const double pi=acos(-);
  9. const int MAXN=3e5;
  10. const double eps=1e-;
  11. struct C
  12. {
  13. double r, i;
  14. C (){}
  15. C(double _r, double _i):r(_r),i(_i){}
  16. inline C operator +(const C a)const{
  17. return C(r+a.r, i+a.i);
  18. }
  19. inline C operator - (const C a)const {
  20. return C(r-a.r, i-a.i);
  21. }
  22. inline C operator * (const C a)const{
  23. return C(r*a.r-i*a.i, r*a.i+i*a.r);
  24. }
  25. }a[MAXN], b[MAXN];
  26. int num[MAXN], cnt[MAXN];
  27. LL res[MAXN], sum[MAXN];
  28.  
  29. void brc(C *y,int l) // 二进制平摊反转置换 O(logn)
  30. {
  31. register int i,j,k;
  32. for(i=,j=l>>;i<l-;i++){
  33. if(i<j) swap(y[i],y[j]); // 交换互为下标反转的元素
  34. // i<j保证只交换一次
  35. k=l>>;
  36. while(j>=k) {// 由最高位检索,遇1变0,遇0变1,跳出
  37. j-=k;
  38. k>>=;
  39. }
  40. if(j<k) j+=k;
  41. }
  42. }
  43. void FFT(C *y,int l,int on) // FFT O(nlogn)
  44. // 其中on==1时为DFT,on==-1为IDFT
  45. {
  46. register int h,i,j,k;
  47. C u,t;
  48. brc(y,l); // 调用反转置换
  49. for(h=;h<=l;h<<=) // 控制层数
  50. {
  51. // 初始化单位复根
  52. C wn(cos(on**pi/h),sin(on**pi/h));
  53. for(j=;j<l;j+=h) // 控制起始下标
  54. {
  55. C w(,); // 初始化螺旋因子
  56. for(k=j;k<j+h/;k++) // 配对
  57. {
  58. u=y[k];
  59. t=w*y[k+h/];
  60. y[k]=u+t;
  61. y[k+h/]=u-t;
  62. w=w*wn; // 更新螺旋因子
  63. } // 据说上面的操作叫蝴蝶操作…
  64. }
  65. }
  66. if(on==-) for(i=;i<l;i++) y[i].r/=l; // IDFT
  67. }
  68.  
  69. int n, L , Max, T;
  70. int main() {
  71. scanf("%d", &T);
  72. while (T--) {
  73. Max = ;
  74. memset(cnt, , sizeof(cnt));
  75. scanf("%d", &n);
  76. for (int i = ; i < n; ++i) {
  77. scanf("%d", num + i);
  78. cnt[num[i]]++;
  79. Max = max(Max, num[i]);
  80. }
  81. ++Max;L = ;
  82. while (L < Max <<) {
  83. L <<= ;
  84. }
  85. for (int i = ; i < Max; ++i) {
  86. a[i] = C(cnt[i], );
  87. }
  88.  
  89. for (int i = Max; i < L; ++i) {
  90. a[i] = C(, );
  91. }
  92. FFT(a, L, );
  93. for (int i = ; i < L; ++i)
  94. a[i] = a[i] * a[i]; // 多项式自乘
  95. FFT(a, L, -);
  96.  
  97. for (int i = ; i < L; ++i) {
  98. res[i] = (LL) (a[i].r + 0.5);
  99. }
  100.  
  101. for (int i = ; i <= Max; ++i)
  102. res[i << ] -= cnt[i];// 自己和自己乘, 即 枚举的是 x+x 的
  103.  
  104. for (int i = ; i < L; ++i)
  105. res[i] >>= ; // x+y 与 y+x 算一次
  106. for (int i = ; i < L; ++i) { //前缀和
  107. sum[i] = sum[i - ] + res[i];
  108. }
  109. double tot = , den = 1.0*n * (n - ) * (n - )/;
  110.  
  111. for (int i = ; i < n; ++i) {
  112. tot += sum[num[i]] / den;// x+y<=z 的个数
  113.  
  114. }
  115. double ans = - tot ;
  116. printf("%.7f\n", ans);
  117. }
  118.  
  119. return ;
  120. }

hdu 4609 3-idiots <FFT>的更多相关文章

  1. 解题:HDU 4609 Three Idiots

    题面 要求组合的方法显然我们需要对桶卷积,即设$F(x)=\sum\limits_{i=1}^{maxx}x^{cnt[i]}$,然后我们初步的先把$F^2(x)$卷出来,表示选两条边.然后我们发现如 ...

  2. 快速傅里叶变换应用之二 hdu 4609 3-idiots

    快速傅里叶变化有不同的应用场景,hdu4609就比较有意思.题目要求是给n个线段,随机从中选取三个,组成三角形的概率. 初始实在没发现这个怎么和FFT联系起来,后来看了下别人的题解才突然想起来:组合计 ...

  3. hdu 4609 3-idiots [fft 生成函数 计数]

    hdu 4609 3-idiots 题意: 给出\(A_i\),问随机选择一个三元子集,选择的数字构成三角形的三边长的概率. 一开始一直想直接做.... 先生成函数求选两个的方案(注意要减去两次选择同 ...

  4. hdu 4609 3-idiots

    http://acm.hdu.edu.cn/showproblem.php?pid=4609 FFT  不会 找了个模板 代码: #include <iostream> #include ...

  5. HDU 4609 3-idiots(FFT)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意:给出n个正整数(数组A).每次随机选出三个数.问这三个数能组成三角形的概率为多大? 思路: ...

  6. HDU 4609 FFT模板

    http://acm.hdu.edu.cn/showproblem.php?pid=4609 题意:给你n个数,问任意取三边能够,构成三角形的概率为多少. 思路:使用FFT对所有长度的个数进行卷积(\ ...

  7. hdu 4609 3-idiots——FFT

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4609 答案就是随便选三条边的方案 - 不合法的方案. 不合法的方案就是算出 x+y = k 的方案数 g[ ...

  8. hdu 4609 3-idiots —— FFT

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=4609 算不合法的比较方便: 枚举最大的边,每种情况算了2次,而全排列算了6次,所以还要乘3: 注意枚举最大 ...

  9. FFT(快速傅里叶变换):HDU 4609 3-idiots

    3-idiots Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

随机推荐

  1. 解决 Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding. 的问题

    在web 网站开发中,经常需要连接数据库,有时候会出现这样的数据连接异常消息: 主要原因是 应用程序与数据库的连接超出了数据库连接的默认时长,在这种情况下,我们可以把数据库连接的时长延长一些,因为 C ...

  2. 解决spawn-fcgi child exited with: 1

    spawn-fcgi -d /data/web/ad/ -f /data/web/ad/code.py -a -P /data/openresty_81/nginx/pid/ad.pid 出错的时候请 ...

  3. 学习总结 java 输入输出流

    思维导图 代码实际演示 package com.hanqi.io; import java.io.*; public class Test1 { public static void main(Str ...

  4. K均值算法实现

    运行环境:Ubuntu+Code::Blocks(G++) K-均值:在D(数据集)中随机地选择k个对象,每个对象代表一个簇的初始均值或中心.对剩下的每个对象,根据其与各个簇中心的欧式距离,将它分配到 ...

  5. coffeeScript 语法总结

    CoffeeScript ---->安装node.js ---->安装coffeeScript 语句: 注意:没有分号,语句由新的一行结束:多条语句写到同一行时需要分号表示一条语句的结束( ...

  6. Leetcode 0025. Reverse Nodes in k-Group

    居然把头插法写错了,debug了一个多小时 /** * Definition for singly-linked list. * struct ListNode { * int val; * List ...

  7. postgresql安装配置

    一,什么是postgresql PostgreSQL是以加州大学伯克利分校计算机系开发的 POSTGRES 版本 4.2 为基础的对象关系型数据库管理系统(ORDBMS),简称pgsql,它支持大部分 ...

  8. CSS 之 Opacity多浏览器透明度兼容处理

    用来设定元素透明度的 Opacity 是CSS 3里的一个属性.当然现在还只有少部分浏览器支持. 不过各个浏览器都有自己的私有属性来支持,其中包括老版本的Mozilla和Safari: IE: fil ...

  9. JS常用的设计模式(9)——策略模式

    策略模式的意义是定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换.一个小例子就能让我们一目了然. 回忆下jquery里的animate方法. $( div ).animate( {&quo ...

  10. 重温CSS:Border属性

    边界是众所周知的,有什么新的东西吗?好吧,我敢打赌,在这篇文章中,有很多你不看永远不知道的东西! 不仅可以用CSS3来创建圆角,使用原有CSS一样可以显示自定义图形.这是正确的(有待考究):在过去,没 ...