有用的学习链接&书籍

傅立叶变化-维基百科

离散傅立叶变化-维基百科·长整数与多项式乘法

维基百科看英文的更多内容&有趣的图

快速傅立叶变化-百度百科,注意其中的图!

组合数学(第4版) Page 287~291(讲得挺详细)

FFT/DFT是个什么东西?

说实话,我也不知道,不过根据维基百科上面的图,就可以略窥一二了:

傅里叶变换将函数的时域(红色)与频域(蓝色)相关联。频谱中的不同成分频率在频域中以峰值形式表示。

——“Fourier transform time and frequency domains (small)”作者Lucas V. Barbosa - 自己的作品。来自维基共享资源 - http://commons.wikimedia.org/wiki/File:Fourier_transform_time_and_frequency_domains_(small).gif#mediaviewer/File:Fourier_transform_time_and_frequency_domains_(small).gif根据公有领域授权

(注,下面的话都是我乱编的,不具有很强的科学性)

它的意思是,红色的周期函数可以通过若干的波(图中蓝色部分)来表示。

FFT的作用就是通过红色的那一部分求出蓝色那一部分。在oi中几乎都是离散函数(你可以认为数组的下标就是定义域),所以oi中用的几乎都是DFT

它的最基本函数是(摘自维基百科):



它们的过程十分相似,我们只要会了DFT,就能套入IDFT了。

注:\(e^{i\theta} = cos \theta + i sin \theta\),没错,这是复数运算,c++中有complex<double>

如果我们按照上面的公式计算,时间复杂度为\(O(n^2)\)。

加快计算

令\(\omega = e^{2 \pi i}\),\(\omega_n^p= e^{ \frac {2 \pi i \cdot p} {n}}\)。

组合数学一书中通过举例子,发现了计算规律(通过化简式子,比如\(\omega^6_4=\omega^2_4\)),发现规律的过程就不展开了。

下面的图片摘自百度百科:



最左边的\(8\)个黑点是原数列,最右边的\(8\)个是输出,没错,输出的下标是有顺序的,但是原数列是无序的(但有规律,看第\(4\)行,左边是\(6=1100_2\),右边是\(3=0011_2\),二进制的字符顺序恰好是反的)。

计算过程可以从代码中看出:

C表示,\(1\)为DFT,\(-1\)为IDFT,MyTypecomplex<double>cnt是数列大小,unit是\(\omega_{cnt}\)。

void FFT(MyType A[], int cnt, int C) {
if (cnt == 1) return; MyType* L = newMemory(cnt >> 1);
MyType* R = newMemory(cnt >> 1); for (int i = 0; i < cnt; i += 2) {
L[i >> 1] = A[i];
R[i >> 1] = A[i + 1];
} FFT(L, cnt >> 1, C);
FFT(R, cnt >> 1, C); MyType w(1, 0);
MyType unit(cos(C * PI * 2 / cnt), sin(PI * 2 / cnt * C));
//also unit(cos( PI * 2 / cnt), sin(PI * 2 / cnt ) * C) for (int i = 0; i < cnt >> 1; i ++) {
A[i] = L[i] + w * R[i];
A[i + (cnt >> 1)] = L[i] - w * R[i];
w *= unit;
}
}

时间复杂度\(O(n * logn)\)。

oi里用DFT来求两个多项式的乘积

算法(此处仅有算法,我不知道它的正确性如何证明):

对于两个多项式\(A\)和\(B\),我们要算出结果\(C\):

  • 对\(A\)进行DFT得到\(\hat{A}\)
  • 对\(B\)进行DFT得到\(\hat{B}\)
  • 令\(\hat C_i = \hat A_i * \hat B_i\)
  • 对\(\hat C\)进行逆DFT(IDFT)得到\(C\)

这篇随笔写得不清不楚的,其实我是想我自己以后看了自己明白。

听说可以写模意义下的DFT(没有误差),找个时间看看??

lyl所说的“总结”图:

附上求两个多项式乘积的代码,注complex的两个值调用分别是real和imag,看这里

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <complex>
#include <assert.h>
using namespace std; const int MAXLOGN = 18;
const int MAXN = 1 << MAXLOGN;
const int MAXMEMORY = MAXLOGN * MAXN;
const double PI = acos(-1.); typedef complex<double> MyType; int n; MyType mem[MAXMEMORY];
MyType* cur_mem; MyType* newMemory(int size) {
cur_mem += size;
return cur_mem - size;
} void FFT(MyType A[], int cnt, int C) {
if (cnt == 1) return; MyType* L = newMemory(cnt >> 1);
MyType* R = newMemory(cnt >> 1); for (int i = 0; i < cnt; i += 2) {
L[i >> 1] = A[i];
R[i >> 1] = A[i + 1];
} FFT(L, cnt >> 1, C);
FFT(R, cnt >> 1, C); MyType w(1, 0);
MyType unit(cos(C * PI * 2 / cnt), sin(PI * 2 / cnt * C)); for (int i = 0; i < cnt >> 1; i ++) {
A[i] = L[i] + w * R[i];
A[i + (cnt >> 1)] = L[i] - w * R[i];
w *= unit;
}
} int main() {
static MyType A[MAXN], B[MAXN];
int cntA, cntB;
scanf("%d%d", &cntA, &cntB);
cntA ++, cntB ++;
for (int i = 0; i < cntA; i ++)
scanf("%lf", &A[i].real());
for (int i = 0; i < cntB; i ++)
scanf("%lf", &B[i].real()); n = 1;
while (n < cntA + cntB - 1) n <<= 1; cur_mem = mem; FFT(A, n, 1);
cur_mem = mem; FFT(B, n, 1);
for (int i = 0; i < n; i ++) A[i] *= B[i];
cur_mem = mem; FFT(A, n, -1); for (int i = 0; i < cntA + cntB - 1; i ++)
printf("%d ", (int) floor(A[i].real() / n + 0.1));
printf("\n");
return 0;
}

初探 FFT/DFT的更多相关文章

  1. 初探FFT在数字图像处理中的应用(fft2函数的用法)

    初探FFT在数字图像处理中的应用 一般FFT在通信等领域都做的一维变换就能够了.可是在图像处理方面,须要做二维变换,这个时候就须要用到FFT2. 在利用Octave(或者matlab)里面的fft2( ...

  2. 傅里叶:有关FFT,DFT与蝴蝶操作(转 重要!!!!重要!!!!真的很重要!!!!)

    转载地址:http://blog.renren.com/share/408963653/15068964503(作者 :  徐可扬) 有没有!!! 其实我感觉这个学期算法最难最搞不懂的绝对不是动态规划 ...

  3. 信号基础知识--FFT DFT

    clc;close all;clear all; f0=10; fs=100;     %采样率 t=1/fs:1/fs:2;         %共两秒钟,共200个采样点.采样间隔T=1/100 y ...

  4. 初探FFT(快速傅里叶变换)

    第一次接触省选的知识点呢!zrf大佬在课堂上讲的非常清楚,但由于本蒟蒻实在太菜了,直接掉线了.今天赶紧恶补一下. 那么这篇博客将分为两块,第一块是FFT的推导和实现,第二块则是FFT在OI上的应用 因 ...

  5. 【CodeVS 3123】高精度练习之超大整数乘法 &【BZOJ 2197】FFT快速傅立叶

    第一次写法法塔,,,感到威力无穷啊 看了一上午算导就当我看懂了?PS:要是机房里能有个清净的看书环境就好了 FFT主要是用了巧妙的复数单位根,复数单位根在复平面上的对称性使得快速傅立叶变换的时间复杂度 ...

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

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

  7. hdu 5730 Shell Necklace [分治fft | 多项式求逆]

    hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...

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

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

  9. BZOJ 4259: 残缺的字符串 [FFT]

    4259: 残缺的字符串 题意:s,t,星号任意字符,匹配方案数 和上题一样 多乘上一个\(a_{j+i}\)就行了 #include <iostream> #include <cs ...

随机推荐

  1. 远程唤醒、WOL、Magic_Packet

    背景:很多人熟悉远程桌面并经常地利用它所带来的方便,但是前提是服务器(远程电脑)必须是处于开机状态.对于机房里有专人管理的服务器,这点不成问题,但如果是放在家里的电脑,要让它7*24地开机似乎就不好办 ...

  2. js中的setTimeout和setInterval

    在html页面中要使用自动刷新功能时,可以是使用js中setTimeout和setInterval: 一.使用方法 setTimeout的使用setTimeout('要调用的Js方法', 调用的延迟时 ...

  3. MongoDB shell常用命令

    Shell操作数据库: 1.  超级用户相关: 1. #进入数据库admin use admin 2. #增加或修改用户密码 db.addUser('name','pwd') 3. #查看用户列表 d ...

  4. HTML5 事件

    下面的表格列出了可插入 HTML 5 元素中以定义事件行为的标准事件属性. Window 事件属性 - Window Event Attributes 表单事件 - Form Events 键盘事件 ...

  5. 织梦dedecms|文章模型内容页标签

    文章标题:{dede:field.title/}文章链接:{dede:field name='arcurl'/}发布时间:{dede:field.pubdate function="MyDa ...

  6. 谈谈Facebook的聊天系统架构

    今天看到一份 Facebook 公司 2009 年的 Slideshow, 介绍它的聊天系统架构, 其中的一张图结构非常清晰, 所以我对这张图谈谈我的看法. Web Tier: 用 PHP 开发, 聊 ...

  7. uvalive 2322 Wooden Sticks(贪心)

    题目连接:2322 Wooden Sticks 题目大意:给出要求切的n个小木棍 , 每个小木棍有长度和重量,因为当要切的长度和重量分别大于前面一个的长度和重量的时候可以不用调整大木棍直接切割, 否则 ...

  8. 奔小康赚大钱(km)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Sub ...

  9. 一个轻client,多语言支持,去中心化,自己主动负载,可扩展的实时数据写服务的实现方案讨论

    背景 背景是设计一个实时数据接入的模块,负责接收client的实时数据写入(如日志流,点击流),数据支持直接下沉到HBase上(兴许提供HBase上的查询),或先持久化到Kafka里.方便兴许进行一些 ...

  10. 制作Orcad的变种BOM(Variant BOM)

    通常在Orcad中画的原理图并不仅仅是用于一款产品.比如一个控制器原理图,可能相应着很多款子产品线,而这些子产品线之间的差别就是通讯口组件不同,少焊几个芯片,或者仅仅是少焊几个电阻. 可是这样交付生产 ...