FFT多项式乘法学习笔记
来源:互联网 发布:编程需要的数学基础 编辑:程序博客网 时间:2024/05/29 05:11
其实我不知道我是否真的理解了FFT,但是我会用FFT优化多项式乘法了QAQ。。
(以下大多摘自算导
前置知识
1. 多项式
在一个代数域F上,关于变量x的多项式定义为形式和形式表示的函数
2. 多项式的次数界
若多项式有非零系数的最高次项为
3. 多项式的表示
(1)系数表示法
对于一个次数界为n的多项式A(x)来说,其系数表示法可以看做是一个列向量
另外,加法运算的时间复杂度是
(2)点值表示法
有n个点
已知点值表示求系数表示称为插值,用拉格朗日插值法可以做到
若次数界为n的多项式A(x),B(x)的n个点的
进入正题。。
1. 单位复根
n次单位复根是满足
平面的原点为圆心的单位圆上,为
因为有
重要性质
相消引理
对任何整数
推论:对任意偶数
折半引理
如果
求和引理
对于任意整数
证明:
原式
2. DFT
A(x)是一个次数界为n的多项式,不失一般性地假定n是2的幂,因为
次数界总是可以增大的。有列向量
3. 快速傅里叶变换(FFT)
FFT是一种可以在
是分治。
定义
所有偶数下标的系数,
所以用
求出
是范德蒙特矩阵。
定理:
证明:
那么有
写的时候发现非递归要比递归快很多。。
递归:
#include<cstdio>#include<iostream>#include<cmath>#include<memory.h>#define N 400010using namespace std;const double pi=acos(-1);struct complex{ double x,i; complex(){} complex(double x,double i):x(x),i(i){} complex operator+(complex a) {return complex(x+a.x,i+a.i);} complex operator-(complex a) {return complex(x-a.x,i-a.i);} complex operator*(complex a) {return complex(x*a.x-i*a.i,x*a.i+i*a.x);}}a[N],b[N];int n,m,i,nn;void fft(complex *a,int n,int t){ if (n==1) return; complex a0[n>>1],a1[n>>1]; for (int i=0;i<n;i+=2) a0[i>>1]=a[i],a1[i>>1]=a[i+1]; fft(a0,n>>1,t);fft(a1,n>>1,t); complex wn(cos(2*pi/n),t*sin(2*pi/n)),w(1,0); for (int i=0;i<(n>>1);i++,w=w*wn) a[i]=a0[i]+w*a1[i],a[i+(n>>1)]=a0[i]-w*a1[i];}int main(){ scanf("%d%d",&n,&m); memset(a,0,sizeof(a));memset(b,0,sizeof(b)); for (i=0;i<=n;i++) scanf("%lf",&a[i].x); for (i=0;i<=m;i++) scanf("%lf",&b[i].x); nn=1;while (nn<=n+m) nn<<=1; fft(a,nn,1);fft(b,nn,1); for (i=0;i<=nn;i++) a[i]=a[i]*b[i]; fft(a,nn,-1); for (i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/nn+0.5));}
非递归:#include<cstdio>#include<iostream>#include<cmath>#include<memory.h>#define N 400010using namespace std;const double pi=acos(-1);struct complex{ double x,i; complex(){} complex(double x,double i):x(x),i(i){} complex operator+(complex a) {return complex(x+a.x,i+a.i);} complex operator-(complex a) {return complex(x-a.x,i-a.i);} complex operator*(complex a) {return complex(x*a.x-i*a.i,x*a.i+i*a.x);}}a[N],b[N];int n,m,i,nn,len,rev[N];void fft(complex *a,int n,int t){ for (int i=0;i<n;i++) if (i<rev[i]) swap(a[i],a[rev[i]]); for (int j=1;j<n;j<<=1) { complex wn(cos(2*pi/(j<<1)),t*sin(2*pi/(j<<1))); for (int i=0;i<n;i+=(j<<1)) { complex w(1,0),t0,t1; for (int k=0;k<j;k++,w=w*wn) t0=a[i+k],t1=w*a[i+j+k],a[i+k]=t0+t1,a[i+j+k]=t0-t1; } }}int main(){ freopen("FFT.in","r",stdin); scanf("%d%d",&n,&m); memset(a,0,sizeof(a));memset(b,0,sizeof(b)); for (i=0;i<=n;i++) scanf("%lf",&a[i].x); for (i=0;i<=m;i++) scanf("%lf",&b[i].x); nn=1;len=0;while (nn<=n+m) nn<<=1,len++; rev[0]=0; for (i=1;i<nn;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(len-1)); fft(a,nn,1);fft(b,nn,1); for (i=0;i<=nn;i++) a[i]=a[i]*b[i]; fft(a,nn,-1); for (i=0;i<=n+m;i++) printf("%d ",(int)(a[i].x/nn+0.5));}
非递归这里有一个翻转的函数,意在让所有数按合并时候的二叉树的叶子节点的顺序排列,不难发现翻转过来就是它的新位置。。- FFT多项式乘法学习笔记
- FFT uoj34 多项式乘法
- FFT与多项式乘法
- FFT uoj34 多项式乘法
- 【Luogu3808】多项式乘法FFT
- [UOJ 34]多项式乘法(FFT)
- [挖坑][uoj]多项式乘法 FFT
- 【FFT优化】[UOJ#34]多项式乘法
- 【UOJ#34】 多项式乘法(FFT && NTT)
- [FFT 模板题] UOJ #34 多项式乘法
- [UOJ#34]多项式乘法(FFT)
- [uoj 34 多项式乘法] FFT&NTT 模板
- FFT模板(UOJ34多项式乘法)
- uoj 34 多项式乘法(fft入门)
- UOJ 34 多项式乘法(FFT)
- [UOJ#34]多项式乘法(FFT)
- [uoj 34 多项式乘法] FFT&NTT 模板
- uoj34 多项式乘法【FFT or NTT】
- 苹果开发 笔记(34)UICollectionView
- 数据结构与算法10: 平衡二叉树AVL(AVL Tree)
- RHEL5.8物理机遇到Read-only file system
- iozone的使用与介绍
- 5.1-1
- FFT多项式乘法学习笔记
- rebar安装出错
- 桥接模式
- n次幂求法
- wampserver Zend Framework 2 alias环境布置
- Win7桌面移到其他磁盘方法
- android中html5页面调取系统摄像头
- zoj2812
- [C++] 使用基于范围的for循环操作string