FFT&NTT(草稿)
来源:互联网 发布:java swing 做登录界面 编辑:程序博客网 时间:2024/04/25 14:30
FFT
FFT(快速傅里叶变换, Fast Fourier Transformation)
在算法竞赛中的主要应用是加速多项式运算。
以多项式乘法为例:朴素算法需要
数学基础
FFT 作为一个数学算法,比起复杂的数据结构,其编程较为简单,但是它对于数学的要求比较高,要想理解此算法必须先有一定的数学基础。
多项式的表示
多项式有两种表示方法:
- 系数表达法
- 点值表达法
其实有些像函数的表达,一二次函数为例,可以用解析式表示,也可以用 3 个以上的点来表示。
系数表达
对于次数界为
点值表达
一个次数界为
使得集合中无重复元素,且
一个多项式可以有很多不同的点值表达,以为可以采用 n 个不同的点
插值:求值计算的逆(从一份多项式的点值表达确定其系数表达的形式)
当差值得多项式的次数界等于已知的点值对的数目,插值才是明确的。
FFT计算过程
有了前面的两个概念,我们的运算流程就十分明确了:
按照朴素算法,时间复杂度:
而按照 FFT 算法,先进行一次 DFT(求值, Discrete Fourier Transform),时间复杂度:
单位复数根
至此,大体的框架已经建成了,但在具体实现还要引入一个单位复数根的概念。
首先,介绍一下复数:
- 我们规定
i2=−1 ,即−1−−−√=i ,其中i 就是虚数域中的单位1; - 复数集
C=R∪I ,是现在已知的最大数集; ∀x∈C,∃a,b∈R 使x=a+b∗i ,其中a 叫做实部,b∗i 叫做虚部;- 实数用一维的数轴表示,而复数需要二维的复平面来表示(类似平面直角坐标系),x轴便是正常的实数数轴,y轴是虚数轴. 坐标为
(a,b) 的点P表示复数a+b∗i 。
下面进入正题:
- n次单位复数根:满足
ωn=1 的复数ω ; - n次单位复数根有恰好有
n 个:对于k=0,1,…,n−1 ,这些根是e2πik/n ; - 根据欧拉公式
eiu=cos(u)+isin(u) n 个单位复数根均匀分布在单位圆的圆周上; - 主n次单位根:
ωn=e2πi/n ,其他所有n次单位复数根都是ωn 的幂次;
根据以上性质,我们可得到以下两个基本性质:
消去引理
对于任何整数
FFT 中需要用到的是
折半引理
如果
即:
折半引理对于用分治策略来对多项式的系数与点值表达法是至关重要的,因为它保证了递归子问题的规模只是递归调用前的一半。
实现思路
其实在数学基础里已经把大体的实现思路有所说明了,这样写是可行的,但是问题在于当数据量很大的时候如果用递归写的话会发生爆栈,所以我们在这里先研究一下递归搜索树,然后进行数组模拟。
我们通过研究系数出现的顺序可以的出变换的规律,于是我们考虑进行二进制 DP
- 当要处理一个
5 位二进制数abcde¯¯¯¯¯¯¯¯ 时,小于abcde¯¯¯¯¯¯¯¯ 的数已经处理好二进制反转了; - 所以
abcde¯¯¯¯¯¯¯¯>>1=abcd¯¯¯¯¯¯ 已有二进制反转0abcd¯¯¯¯¯¯¯¯ ; - 所以只需处理
e¯ 这一位即可; - 那么只需
0abcd¯¯¯¯¯¯¯¯ | ( (abcde¯¯¯¯¯¯¯¯ &1)<<(bit-1)) 即可; - 考虑到 DP 从
0 开始无需反转,1>>1=0 。
之后至于 IDFT 的实现十分神奇,总之最后的答案一定要除以n,由于涉及到精度问题最后强制转换前加上 0.5 。
int(a[i].real()/n+0.5)
代码实现
#include<iostream>#include<cstdio>#include<cmath>#include<complex>using namespace std;typedef complex<double> C;const int MAXN=262145;const double PI=acos(-1);int pos[MAXN],bit,n,m;C a[MAXN],b[MAXN];void FFT(C * A,int type){ int i,j,k; for(i=1;i<n;i++) if(i<pos[i]) swap(A[i],A[pos[i]]); for(i=1;i<n;i<<=1) { C wn(cos(PI/i),type*sin(PI/i)); for(j=0;j<n;j+=i<<1) { C w(1,0); for(k=0;k<i;k++,w*=wn) { C x=A[j+k],y=w*A[i+j+k]; A[j+k]=x+y,A[i+j+k]=x-y; } } }}int main(){ scanf("%d%d",&n,&m); int i,x; for(i=0;i<=n;i++) scanf("%d",&x),a[i]=x; for(i=0;i<=m;i++) scanf("%d",&x),b[i]=x; m+=n; for(n=1;n<m;n<<=1) ++bit; for(i=1;i<n;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(bit-1)); FFT(a,1),FFT(b,1); for(i=0;i<=n;i++) a[i]*=b[i]; FFT(a,-1); for(i=0;i<=m;i++) printf("%d ",int(a[i].real()/n+0.5)); return 0;}
- FFT&NTT(草稿)
- fft & ntt
- FFT-NTT
- fft/ntt
- 【UOJ#34】 多项式乘法(FFT && NTT)
- FFT/NTT 总结(HDU 4656)
- 初识FFT和NTT
- BZOJ2179【FFT】【NTT】
- [UOJ34]FFT && NTT 模板
- FFT、NTT小结
- FFT,NTT学习笔记
- FFT及NTT模板
- hiho1388 FFT/NTT
- FFT & NTT学习心得
- FFT&&FWT&&NTT
- HDU4609 NTT||FFT
- FFT & NTT 学习 模板
- 快速傅里叶变换(FFT)和数论变换(NTT)模板
- Keras实现LeNet-5网络,并可视化网络结构图
- 归并排序的实现
- 学习记录-使用QTabWidget在析构时需要注意的问题
- kafka入门:简介、使用场景、设计原理、主要配置及集群搭建(转)
- MyEclipse连接SQL Server 2008数据库的操作方法
- FFT&NTT(草稿)
- Python开发web服务器——留言板
- 配置式的javamail
- 子树
- POJ 2385 Apple Catching
- 计算log(N!)
- java基础总结08-面向对象4(static关键字)
- 一个成年人的自我修养(有感而发,内容较少)
- ehcache中CacheManager.create()崩溃遇到的问题,解决方案