快速傅里叶变化有不同的应用场景,hdu4609就比较有意思。题目要求是给n个线段,随机从中选取三个,组成三角形的概率。

初始实在没发现这个怎么和FFT联系起来,后来看了下别人的题解才突然想起来:组合计数问题可以用多项式的卷积来解决。于是将给的数据进行卷积相乘,利用FFT即可求出三角形任意两条线段组合的可能数目。

然后遍历初始数据,将其作为最长边(这里一开始也没想明白,其实就是只要最长边大于短边之和,其他两个不等式也自然可以满足)。那么理论上说比它长的所有两边组合可能都可以。当然在这里要考虑三种特殊情况:(即在两边组合数目中减去这些情况)

1.这两个边有可能一个边比最长边长,一个边小于最长边

2.其中一个边就是要选的这个边

3.两个边其实都比最长边长,这种情况要除以二

PS:G++使用的是longlong类型,C++是_int64,好久没写忘记了。

longlong在代码中间乘的运算也要加上,否则还是会出错。

#include <iostream>
#include <cmath>
#include <algorithm> //spell!
#include <string.h>
#define MAXN 400040
#define PI acos(-1.0)
using namespace std; struct complex
{
double r,i;
complex(double real=0.0,double image=0.0)
{
r=real;
i=image;
}
//以下为三种虚数运算的定义
complex operator+(const complex o)
{
return complex(r+o.r,i+o.i);
}
complex operator-(const complex o)
{
return complex(r-o.r,i-o.i);
}
complex operator*(const complex o)
{
return complex(r*o.r-i*o.i,r*o.i+i*o.r);
}
}x1[MAXN]; void bitrev(complex *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(complex *in,int n,int flag)
{
int i,j,k;
complex u,t;
bitrev(in,n);
for(int i=;i<=n;i=i*)
{
complex wn(cos((*PI*flag)/i),sin((*PI*flag)/i));//初始化单位复根
for(j=;j<n;j=j+i)
{
complex w(,);
for(k=j;k<j+i/;k++)
{
u=in[k];
t=w*in[k+i/];
in[k]=u+t;
in[k+i/]=u-t;
w=w*wn;
}
}
}
if(flag==-)
for(int i=;i<n;i++)
in[i].r=in[i].r/n;
} int a[];
long long res[MAXN];
long long sum[MAXN];
long long num[MAXN];
int main() {
int T;
scanf("%d",&T);
while(T--)
{
int n,i;
scanf("%d",&n);
memset(res,,sizeof(res));
memset(sum,,sizeof(sum));
memset(num,,sizeof(num));
for(int j=;j<n;j++)
{
scanf("%d",&a[j]);
num[a[j]]++;
}
sort(a,a+n);
for(i = ;i <=a[n-];i++)
{
x1[i].r=num[i];
x1[i].i=;
}
int expandn=;
while(expandn<*(a[n-]+))expandn=expandn*; for(i = a[n-]+;i<expandn;i++)
{
x1[i].r=;
x1[i].i=;
}
fft(x1,expandn,);
for(i=;i<expandn;i++)
x1[i]=x1[i]*x1[i];
fft(x1,expandn,-);
for(i=;i<expandn;i++)
{
res[i]=(long long)(x1[i].r+0.5);
}
//去除本身
for(i=;i<n;i++)
res[a[i]+a[i]]--;
//变为组合
for(i=;i<expandn;i++)
res[i]=res[i]/;
//求出两边之和为i的所有可能
//expandn=(a[n-1]+1)*2;
sum[]=res[];
for(i=;i<expandn;i++)
sum[i]=res[i]+sum[i-];
long long ans=;
for(i=;i<n;i++)
{
ans+=sum[expandn-]-sum[a[i]];//比长度为a[i]大的所有可能
//去除一个大于a[i],一个小于a[i]
ans=ans-(long long)(n--i)*i;
//去除一个取自己
ans=ans-(n-);
//去除取两个都大
ans=ans-(long long)(n--i)*(n--i)/;
}
long long all = (long long)n*(n-)*(n-)/;
printf("%.7lf\n",(double)ans/all);
}
}

hdu 4609

快速傅里叶变换应用之二 hdu 4609 3-idiots的更多相关文章

  1. 基于python的快速傅里叶变换FFT(二)

    基于python的快速傅里叶变换FFT(二)本文在上一篇博客的基础上进一步探究正弦函数及其FFT变换. 知识点  FFT变换,其实就是快速离散傅里叶变换,傅立叶变换是数字信号处理领域一种很重要的算法. ...

  2. 解题:HDU 4609 Three Idiots

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

  3. HDU 1402 A * B Problem Plus 快速傅里叶变换 FFT 多项式

    http://acm.hdu.edu.cn/showproblem.php?pid=1402 快速傅里叶变换优化的高精度乘法. https://blog.csdn.net/ggn_2015/artic ...

  4. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

  5. 「快速傅里叶变换(FFT)」学习笔记

    FFT即快速傅里叶变换,离散傅里叶变换及其逆变换的快速算法.在OI中用来优化多项式乘法. 本文主要目的是便于自己整理.复习 FFT的算法思路 已知两个多项式的系数表达式,要求其卷积的系数表达式. 先将 ...

  6. 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/常用套路【入门】

    原文链接https://www.cnblogs.com/zhouzhendong/p/Fast-Fourier-Transform.html 多项式 之 快速傅里叶变换(FFT)/数论变换(NTT)/ ...

  7. 快速傅里叶变换(FFT)

    扯 去北京学习的时候才系统的学习了一下卷积,当时整理了这个笔记的大部分.后来就一直放着忘了写完.直到今天都腊月二十八了,才想起来还有个FFT的笔记没整完呢.整理完这个我就假装今年的任务全都over了吧 ...

  8. 研究傅里叶变换的一本好书<<快速傅里叶变换及其C程序>>

    快速傅里叶变换及其C程序 <快速傅里叶变换及其C程序>是中国科学技术大学出版社出版的.本书系统地介绍了傅里叶变换的理论和技术,内容包括傅里叶变换(FT)的定义.存在条件及其性质,离散傅里叶 ...

  9. 快速傅里叶变换(FFT)学习笔记(未完待续)

    目录 参考资料 FFT 吹水 例题 普通做法 更高大尚的做法 定义与一部分性质 系数表达式 点值表达式 点值相乘??? 卷积 复数 单位根 DFT IDFT 蝴蝶迭代优化 单位根求法 实现.细节与小优 ...

随机推荐

  1. Java-线程间通信

    Java-线程间通信 一 线程通讯 就是多个线程操作同一个资源,可是操作的动作不同 二 停止线程: 控制住run的循环就能够控制线程结束 当线程处于冻结状态,就不会读取标记,线程就不会结束 inter ...

  2. java解析xml的几种方式

    java解析xml的几种方式 DOM DOM的全称是Document ObjectModel,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称D ...

  3. Android项目导入时,出现的Could not write file 。。。。。。.classpath错误解决办法

    导入到Eclipse中后选择了相应的API后,红叉的项目错误没有了. 工程列表也无任何错误了.但出现了这样的提示框错误 说明的是.classpath这个环境文件不能写.随后,查看工程文件主目录下的.c ...

  4. GCD详细使用笔记

    第一.通过GCD创建队列(Queue) 创建队列方式有以下几种: 1.创建一个串行队列: dispatch_queue_t queue =dispatch_queue_create("串行队 ...

  5. mysql root密码重置

    1.修改my.cnf #位置一般是 /etc/my.cnf 2.重启mysql服务 service mysqld restart 3.进入mysql mysql -uroot -p 然后直接回车 4. ...

  6. phpcms v9附件上传后显示链接名称如何改为附件名称?

    使用phpcms v9的朋友都知道,v9在后台添加内容的时候上传附件显示的是一个链接,这样太不人性化了,那怎么显示文件名称呢 ?小编以前发布文章的时候都是上传后复制链接在给文字加上超链接的,这样非常的 ...

  7. python优秀库 - 使用envelopes发送邮件

    这里有一个使用python自带lib发送邮件的例子(http://my.oschina.net/leejun2005/blog/74416),这里面讲解的很全面,可以供大家参考. 今天将的是使用env ...

  8. Dapper 基础用法

    Dapper是.Net下的一个简单orm框架,具有以下特点: 1.简单,只需要一个文件即可(SqlMapper.cs) 2.快速,下面是一个查询结果集在500以上的运行速度对比 3.不要求特定的db ...

  9. ASP.NET jQuery 随笔 显示CheckBoxList成员选中的内容

    通过jQuery来获取CheckBoxList成员内容. <%@ Page Language="C#" AutoEventWireup="true" Co ...

  10. oracle序列详解

    tyle="margin:20px 0px 0px; font-size:14px; line-height:26px; font-family:Arial"> 序列: 是o ...