有用的学习链接&书籍

傅立叶变化-维基百科

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

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

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

组合数学(第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. js 从一个json拼接成另一个json,并做json数据分页table展示

    先给数据: //原始json数据json = [{"id":"1","aid":"013","performa ...

  2. YII2 实现登录时候修改最新登录时间

    YII2 实现登录时候修改最新登录时间 YII2保存最新登录时间主要技巧:为 EVENT_AFTER_LOGIN 事件绑定一个方法,在方法中保存最新时间 public function login() ...

  3. codeforces 623A. Graph and String 构造

    题目链接 给出一个图, 每个节点只有三种情况, a,b, c. a能和a, b连边, b能和a, b, c,连边, c能和b, c连边, 且无重边以及自环.给出初始的连边情况, 判断这个图是否满足条件 ...

  4. KbmMW资源汇总(更新中…)

    KbmMW框架是收费的,不在此提供下载,如需购买,请自行联系作者Kim Madsen. 网址资源: 官网主页:http://www.components4programmers.com/product ...

  5. [置顶] android网络通讯之HttpClient4不指定参数名发送Post

    在HttpClient4之前都是通过List<NameValuePair>键值对的形式来向服务器传递参数 ,在4.0版本中在加入了不指定参数名发送数据的形式,利用StringEntity来 ...

  6. 玩转Linux网络namespace-单机自环測试与策略路由

    上周有厂商到公司測试,拿了一块据说非常猛的网络处理加速PCIe板卡,拎在手里沉甸甸的非常有分量,最让人意淫的是那4个万兆光口,于是我迫不及待的想要一览光口转发时那种看不见的震撼. 可是,仅凭4个光口怎 ...

  7. hdu4597 Play Game(DFS)

    转载请注明出处:http://blog.csdn.net/u012860063 题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=4597 题意 Alic ...

  8. dhtmlx之dhtmlXGrid显示数据

    引用 <link href="../../dhtmlXGridScripts/dhtmlxgrid.css" rel="stylesheet" type= ...

  9. AsyncQueryHandler处理数据

    参考:http://blog.csdn.net/hfreeman2011/article/details/8555474和http://blog.csdn.net/dragondog/article/ ...

  10. ZOJ 1893 A Multiplication Game 【简单博弈】

    感觉ZJU上有不少博弈的题目. 这道题目还是比较好理解的,题目大概意思是:两人轮流乘一个2-9的数,从1开始乘,求谁的乘积先大于N. 还是寻找必败点必胜点,不过在这个题目里转换成了寻找必败区间必胜区间 ...