链接: 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 的值, 系数即为 方案数, 减去不合法的即为所求~

 #include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef __int64 LL;
const double pi=acos(-);
const int MAXN=3e5;
const double eps=1e-;
struct C
{
double r, i;
C (){}
C(double _r, double _i):r(_r),i(_i){}
inline C operator +(const C a)const{
return C(r+a.r, i+a.i);
}
inline C operator - (const C a)const {
return C(r-a.r, i-a.i);
}
inline C operator * (const C a)const{
return C(r*a.r-i*a.i, r*a.i+i*a.r);
}
}a[MAXN], b[MAXN];
int num[MAXN], cnt[MAXN];
LL res[MAXN], sum[MAXN]; void brc(C *y,int l) // 二进制平摊反转置换 O(logn)
{
register int i,j,k;
for(i=,j=l>>;i<l-;i++){
if(i<j) swap(y[i],y[j]); // 交换互为下标反转的元素
// i<j保证只交换一次
k=l>>;
while(j>=k) {// 由最高位检索,遇1变0,遇0变1,跳出
j-=k;
k>>=;
}
if(j<k) j+=k;
}
}
void FFT(C *y,int l,int on) // FFT O(nlogn)
// 其中on==1时为DFT,on==-1为IDFT
{
register int h,i,j,k;
C u,t;
brc(y,l); // 调用反转置换
for(h=;h<=l;h<<=) // 控制层数
{
// 初始化单位复根
C wn(cos(on**pi/h),sin(on**pi/h));
for(j=;j<l;j+=h) // 控制起始下标
{
C w(,); // 初始化螺旋因子
for(k=j;k<j+h/;k++) // 配对
{
u=y[k];
t=w*y[k+h/];
y[k]=u+t;
y[k+h/]=u-t;
w=w*wn; // 更新螺旋因子
} // 据说上面的操作叫蝴蝶操作…
}
}
if(on==-) for(i=;i<l;i++) y[i].r/=l; // IDFT
} int n, L , Max, T;
int main() {
scanf("%d", &T);
while (T--) {
Max = ;
memset(cnt, , sizeof(cnt));
scanf("%d", &n);
for (int i = ; i < n; ++i) {
scanf("%d", num + i);
cnt[num[i]]++;
Max = max(Max, num[i]);
}
++Max;L = ;
while (L < Max <<) {
L <<= ;
}
for (int i = ; i < Max; ++i) {
a[i] = C(cnt[i], );
} for (int i = Max; i < L; ++i) {
a[i] = C(, );
}
FFT(a, L, );
for (int i = ; i < L; ++i)
a[i] = a[i] * a[i]; // 多项式自乘
FFT(a, L, -); for (int i = ; i < L; ++i) {
res[i] = (LL) (a[i].r + 0.5);
} for (int i = ; i <= Max; ++i)
res[i << ] -= cnt[i];// 自己和自己乘, 即 枚举的是 x+x 的 for (int i = ; i < L; ++i)
res[i] >>= ; // x+y 与 y+x 算一次
for (int i = ; i < L; ++i) { //前缀和
sum[i] = sum[i - ] + res[i];
}
double tot = , den = 1.0*n * (n - ) * (n - )/; for (int i = ; i < n; ++i) {
tot += sum[num[i]] / den;// x+y<=z 的个数 }
double ans = - tot ;
printf("%.7f\n", ans);
} return ;
}

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. freeglut第一步

    #include <GL/freeglut.h> static void RenderSceneCB() { glClear(GL_COLOR_BUFFER_BIT); glutSwapB ...

  2. VR就是下一个浪潮_2016 (GMGC) 全球移动游戏大会观后感

    "VR就是下一个浪潮"  --2016 (GMGC) 全球移动游戏大会观后感   早在2014年参会Unity举办的一年一度的金立方盛典大会,就初次体验了VR头盔设备,于是印象深刻 ...

  3. docker学习笔记1 -- 安装和配置

    技术资料 docker中文官网:http://www.docker.org.cn/ 中文入门课程:http://www.docker.org.cn/book/docker.html docker学习笔 ...

  4. opencv_协方差矩阵与协方差讲解

    统计学的基本概念 学过概率统计的孩子都知道,统计里最基本的概念就是样本的均值,方差,或者再加个标准差.首先我们给你一个含有n个样本的集合,依次给出这些概念的公式描述,这些高中学过数学的孩子都应该知道吧 ...

  5. 解决服务器复制中SID冲突问题

    解决服务器复制中SID冲突问题 如果你有多部的主机需要安装,最快的方法是什么?想必就是用像GHOST之类的软件来进行硬盘的复制.当然,如果是安装在虚拟机之中,则需要复制虚拟的硬盘档案即可,以微软的VP ...

  6. Windows phone 8 学习笔记(1) 触控输入(转)

    Windows phone 8 的应用 与一般的Pc应用在输入方式上最大的不同就是:Windows phone 8主要依靠触控操作.因此在输入方式上引入一套全新的触控操作方式,我们需要重新定义相关的事 ...

  7. ORA-12518 TNS:监听程序无法分发客户机连接 解决办法

    查询的脚本: select count(*) from v$process; --取得数据库目前的进程数. select value from v$parameter where name = 'pr ...

  8. js实现文字截断

    先前用jq做了一个文字截断功能,但是不用jq的项目要实现此功能还要引如jq显得过于麻烦.这里写了一个js的文字截断功能.直接上代码. HTML(测试用的): <div>我是pox我是pox ...

  9. SqlServer存储过程学习笔记(增删改查)

    * IDENT_CURRENT 返回为任何会话和任何作用域中的特定表最后生成的标识值. CREATE PROCEDURE [dbo].[PR_NewsAffiche_AddNewsEntity] ( ...

  10. Send User to a Portal Folder

    Sometimes you would want to give users the option to click a button on the page and send them back t ...