FFT学习笔记

前言

基本没写过笔记这种东西,但是FFT这东西一开始就摧毁了我的智商,写写加深印象吧。
多亏了yhzq+yveh的笔记帮助,总算是明白一些了,以下部分内容引自二位dalao


前置知识

多项式定义

x x 为变量的多项式是定义在一个代数域F上,将函数 A(x) A ( x ) 表示为形式和

A(x)=n1i=0aixi A ( x ) = ∑ i = 0 n − 1 a i x i

我们称 a0,a1,a2an1 a 0 , a 1 , a 2 ⋯ a n − 1 为多项式的系数。所有的系数都属于F,比如复数域C。

如果一个多项式 A(x) A ( x ) 的最高次项系数为 ak a k ,那我们称 A(x) A ( x ) 的次数为 k k ,记作degree(A)=k

多项式运算

单点求值

这个数学老师也告诉我们啦,秦九韶公式嘛

y=a0+a1x+a2x2+...+anxn y = a 0 + a 1 x + a 2 x 2 + . . . + a n x n

=a0+x(a1+x(a2+...)) = a 0 + x ( a 1 + x ( a 2 + . . . ) )

多项式加法

这个比较好想啦,就是次数相同的每一项相加

C(x)=A(x)+B(x)=n1i=0aixi+n1j=0bjxj=n1k=0ckxk C ( x ) = A ( x ) + B ( x ) = ∑ i = 0 n − 1 a i x i + ∑ j = 0 n − 1 b j x j = ∑ k = 0 n − 1 c k x k

多项式乘法

就是将 A(x) A ( x ) 中的每一项与 B(x) B ( x ) 中的每一项相乘,然后同类项合并,举个栗子
这里写图片描述
差不多是高精乘的影子了

C(x)=2n2i=0cixi C ( x ) = ∑ i = 0 2 n − 2 c i x i

ci=ij=0aibij c i = ∑ j = 0 i a i b i − j

显然 degree(C)=degree(A)+degree(B) d e g r e e ( C ) = d e g r e e ( A ) + d e g r e e ( B )

多项式表示

多项式的表示方法有两种:系数表示,点值表示
系数表示的加法是 O(n) O ( n ) ,乘法却是 O(n2) O ( n 2 )

那么点值表示是什么呢?从函数的角度考虑,对于一次函数,两点可以确定,那么只要我们用n个不同的点来表示的话

(x0,y0),(x1,y1),,(xn1,yn1) ( x 0 , y 0 ) , ( x 1 , y 1 ) , ⋯ , ( x n − 1 , y n − 1 )

多项式也是唯一的
加法的时候就是把每个点加上
(x0,y0+y0'),(x1,y1+y1'),(x2n1,y2n1+y2n1') ( x 0 , y 0 + y 0 ′ ) , ( x 1 , y 1 + y 1 ′ ) , ⋯ ( x 2 n − 1 , y 2 n − 1 + y 2 n − 1 ′ )

复杂度 O(n) O ( n )

乘法呢?
因为 degree(C)=degree(A)+degree(B) d e g r e e ( C ) = d e g r e e ( A ) + d e g r e e ( B ) ,此时我们必须找到2n个点表示多项式,所以需要对 A,B A , B 的点值拓展,给定A的拓展式:

(x0,y0),(x1,y1),(x2n1,y2n1) ( x 0 , y 0 ) , ( x 1 , y 1 ) , ⋯ ( x 2 n − 1 , y 2 n − 1 )

再给出B的:
(x0,y0),(x1,y1),(x2n1,y2n1) ( x 0 , y 0 ′ ) , ( x 1 , y 1 ′ ) , ⋯ ( x 2 n − 1 , y 2 n − 1 ′ )

这样可以得到C:
(x0,y0y0'),(x1,y1y1'),(x2n1,y2n1y2n1') ( x 0 , y 0 y 0 ′ ) , ( x 1 , y 1 y 1 ′ ) , ⋯ ( x 2 n − 1 , y 2 n − 1 y 2 n − 1 ′ )

也是优越的O(n)

复数

基本知识

复数,为实数的延伸,它使任一多项式方程式都有根。通常表示为 a+bi a + b i ,a,b为实数,且 1=i − 1 = i ,a为它的实部,b为它的虚部

复平面,是x轴表示实数与y轴(除了原点)表示虚数,建立起来的复数的几何表示。

每一个复数 a+bi a + b i 都能表示为一个 (0,0) ( 0 , 0 ) 指向 (a,b) ( a , b ) 的向量。
这里写图片描述

这里写图片描述
这里写图片描述
引理2—–消去引理
引理3—–折半引理
还有引理4—–求和引理
这里写图片描述
这里写图片描述

FFT

思想

终于到FFT了,它做了一件什么事呢?
系数表达–>点值表达–>计算乘法–>点值表达–>系数表达,运用了高效的插值使总时间复杂度为O(nlogn)
这里写图片描述

过程

DFT

系数表达–>点值表达
为了方便,下面的n都是2^x,不足的把系数用0补
这里写图片描述

FFT计算

这里写图片描述
这里写图片描述

IDFT

点值表达–>系数表达
逆矩阵
单位矩阵
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

实现方法

这里写图片描述
这里写图片描述
这里写图片描述

代码:

例题

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
const int N=300005;
const double pi=acos(-1.0);
struct complex
{
    double x,y;
    complex(double X=0,double Y=0){x=X; y=Y;}
}a[N],b[N];
int n,m,L,r[N];
complex operator +(complex a,complex b){return complex(a.x+b.x,a.y+b.y);}
complex operator -(complex a,complex b){return complex(a.x-b.x,a.y-b.y);}
complex operator *(complex a,complex b){return complex(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
void FFT(complex *a,int id)
{
    for (int i=0;i<n;i++) 
     if (i<r[i]) swap(a[i],a[r[i]]);
    for (int k=1;k<n;k<<=1)
    {
        complex wn=complex(cos(pi/k),id*sin(pi/k));
        for (int i=0;i<n;i+=(k<<1))
        {
            complex w=complex(1,0);
            for (int j=0;j<k;j++,w=w*wn)
            {
                complex x=a[i+j],y=w*a[i+j+k];
                a[i+j]=x+y; a[i+j+k]=x-y;
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=0;i<=n;i++) scanf("%lf",&a[i].x);
    for (int i=0;i<=m;i++) scanf("%lf",&b[i].x);
    m+=n;
    for (n=1;n<=m;n<<=1) ++L;
    for (int i=0;i<n;i++)
      r[i]=(r[i>>1]>>1) | ((i&1)<<L-1); 
    FFT(a,1); FFT(b,1);
    for (int i=0;i<=n;i++) a[i]=a[i]*b[i];
    FFT(a,-1);
    for (int i=0;i<=m;i++) printf("%d ",(int)(a[i].x/n+0.5));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值