首先感谢Duan2baka大佬,给我讲的非常透彻,大家如果没看懂我写的可以看一下他的—>点这里
概念
咱们先来了解一些非常重要的概念(好吧其实我只是凑字,但了解一下也是很好的)
FFT
多项式函数
卷积
大家可能会想,这三个毫不相干的概念有什么联系呢?
其中,多项式乘法可以用卷积来表示。
事实上,在oi中,卷积都可以用FFT优化。
下面我们来看一下,FFT是怎么优化卷积的(为了方便起见,我们探究多项式乘法)
暴力
大家应该都会,多项式与多项式相乘,先用一个多项式的每一项与另一个多项式的每一项相乘,再把所得的积相加 (初中时背的滚瓜烂熟)
用式子可以表示为
其中
是卷积的常见形式,大家以后如果看见这样的柿子就不要多想,尽情地FFT吧
好了,我相信大家O()的算法都会,我就不多说了,下面我要讲的是O()的优化
预备知识
复数
话不多说,直接上
补充一下,
复数是无序的,但也有四则运算,
大家这么聪明,我相信都会
那好吧,就讲一下
每个复数都可以表示成为复平面上的一个点(也可以说是一个向量)
其中与x轴的夹角称为福角
到x轴距离称为模长
先来一张图
同时,复数的运算法则和实数是一样的(:那你还说一大堆废话干什么:)
但是!复数的乘法却有其独特的意义
我们设 复数z1=a1+b1*i,z2=a2+b2*i
所以z1*z2=(a1+b1*i)*(a2+b2*i)
复数*复数,模长相乘,幅角相加
单位根
一个复数W,满足,那么我们就说w是n次单位根,记作,
(特别提醒一下,表示第k个单位根,我学的时候纠结半天)
易证n次单位根共有n个
那么我们看一下4次单位根在复平面上的表示
8次单位根
此处借用duan2baka大佬两张图
很好,你们现在可以想一下三角函数。是不是很像?
so,我们有了两个重要的定理
注意负号
解释一下,第一个就是左右等式分单位圆的比例是一样的
第二个左右等式关于原点对称
很好,这两个定理对后面推结论很有帮助
多项式的表达方法
系数表达法
就是平时数学写的,在此不赘述
点值表达法
我们把n+1不同个点带入n次多项式,得到点集S={p1,p2,...,pn+1},这个点集就是多项式的点值表达法。
为什么要学点值表达法?
当两个多项式相乘时,设这两个多项式的点集分别为S1,S2
如果S1,S2中代入的点的横坐标全部相同,那么我们就可以把这些纵坐标乘起来作为新多项式的点
而点值相乘时间复杂度是O(n)的,这样我们就可以快速相乘。但是我们需要把n+1个点带入,这个的时间复杂度是O的,我们需要找一种能在更短时间内求出n个点值的方法
下面进入正题
FFT
FFT有三个过程,求值(DFT),相乘,插值(IDFT)
当然,我们可以代入任何n+1个值,但是我们需要加速乘法,就需要寻找n+1个之间有关系的值代入,这样看看能不能简化运算
推公式时间到
设A(X)为多项式,则
此处再次借用duan2推导(我打不出来这种公式)
我们发现,知道A0和A1,我们就能推出A()和A(),我们称其为蝴蝶变换
所以一直递归下去就好了,时间复杂度O(n log n )
注意由于最后是按奇偶分类,所以我们的多项式需要补齐到位,补齐的位系数为0就可以了
但我们发现,递归时间复杂度太大,所以我们有了迭代的写法
我们先看一下递归是怎么进行的
我们发现,在递归的最后,被放在了它二进制颠倒的位置
所以我们先求出最后一行,再往上迭代
二进制翻转rader代码如下
void rader(Complex* a,int len)
{
int j=len>>1;
for(int i=1;i<len-1;i++)
{
if(i<j)swap(a[i],a[j]);
int k=len>>1;
while(j>=k)
{
j-=k;
k>>=1;
}
if(j<k)j+=k;
}
}
不懂的—>
传送门
迭代写法
void fft(Complex* a,int len,int on)
{
rader(a,len);
for(int ll=2;ll<=len;ll*=2)
{
double ang=on*2*PI/ll;
Complex wn(cos(ang),sin(ang));
for(int i=0;i<len;i+=ll)
{
Complex w(1.0,0.0);
for(int j=i;j<i+ll/2;j++)
{
Complex u=a[j];
Complex t=w*a[j+ll/2];
a[j]=u+t;
a[j+ll/2]=u-t;
w=w*wn;
}
}
}
if(on==-1)
{
for(int i=0;i<len;i++)
a[i].real/=len;
}
}
细心的同学可能发现了,这里面的on很奇怪,这就是我们讲的下一个内容——插值
插值
我们发现,只要把换成,就是对虚部取相反数,结果再除以len,就相当于插值了(这太好了)
代码同上,DFT on=1,IDFT on=-1
FFT到这里就讲完了!
————————————
是不是很爽
来两道例题
某c姓童鞋:这题我压位高精一样ac!
那如果改成1e5呢?
唉??这不就是FFT裸题吗???
来一波,最后四舍五入,别忘了进位
我们可以生成函数,则
这不就是卷积吗??
fft直接上
——————————————
好了FFT讲完了,这也是我的第一篇blog,希望大佬多多包涵,也希望指出本文的错误,一起进步!