FFT快速傅里叶变换 [模板]

本文深入讲解了快速傅立叶变换(FFT)算法的核心原理及应用,包括单位根的概念、FFT的数学基础、算法实现及复杂度分析。通过将多项式转换为点值表示,FFT实现了高效的多项式卷积计算,广泛应用于信号处理、图像处理等领域。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • F F T 的 作 用 FFT的作用 FFT

O ( l o g N ) O(logN) O(logN) 计算两个多项式的卷积 .

  • F F T 的 前 置 FFT的前置 FFT

  1. 单位根

单 位 根 为 在 单 位 圆 上 的 点 . 横 坐 标 为 实 部 , 纵 坐 标 为 虚 部 的 复 数 . 单位根为在单位圆上的点.\\ 横坐标为实部, 纵坐标为虚部的复数 . .,.


如图, 图中落在 x x x 正半轴的那个红点称为 w n 0 w_{n}^0 wn0, 被称为 n n n 次单位根, 其余的点从 w n 0 w_n^0 wn0 逆时针顺序分别称为 w n 1 , w n 2 . . . w n 7 w_n^1, w_n^2...w_n^7 wn1,wn2...wn7 .

从图中可以 感性 得到 单位根 2 2 2 个性质 ↓ \downarrow

  • 性 质 1 : 性质1: 1: w 2 n 2 k = w n k w_{2n}^{2k}=w_n^k w2n2k=wnk

  • 性 质 2 : 性质2: 2: w n k + n 2 = − w n k w_n^{k+\frac{n}{2}} = -w_n^k wnk+2n=wnk


下面给出 理性 证明, 首先要知道

欧 拉 公 式 : w n k = c o s ( k ∗ 2 π n ) + i ∗ s i n ( k ∗ 2 π n ) 欧拉公式:w_n^k=cos(k*\frac{2 \pi}{n}) + i*sin(k*\frac{2 \pi}{n}) :wnk=cos(kn2π)+isin(kn2π)

其中 i i i − 1 \sqrt{-1} 1 .


  • 性 质 1 : 性质1: 1: w 2 n 2 k = w n k w_{2n}^{2k}=w_n^k w2n2k=wnk
    证 : 证: :
    w 2 n 2 k = c o s ( 2 k ∗ 2 π 2 n ) + i ∗ s i n ( 2 k ∗ 2 π 2 n ) = w n k w_{2n}^{2k} = cos(2k*\frac{2 \pi}{2n}) + i*sin(2k*\frac{2 \pi}{2n})=w_n^k w2n2k=cos(2k2n2π)+isin(2k2n2π)=wnk

  • 性 质 2 : 性质2: 2: w n k + n 2 = − w n k w_n^{k+\frac{n}{2}} = -w_n^k wnk+2n=wnk
    证 : 证: :
    w n k + n 2 = c o s [ ( k + n 2 ) ∗ 2 π n ] + i ∗ s i n [ ( k + n 2 ) ∗ 2 π n ) ] = − w n k w_n^{k+\frac{n}{2}}\\ =cos[(k+\frac{n}{2})*\frac{2\pi}{n}]+i*sin[(k+\frac{n}{2})*\frac{2\pi}{n})]\\ =-w_n^k wnk+2n=cos[(k+2n)n2π]+isin[(k+2n)n2π)]=wnk

  • F F T 的 内 容 FFT的内容 FFT

  • 有多项式 A ( x ) = a 0 + a 1 x + a 2 x 2 +  ⁣ ⋯ + a n − 1 x n − 1 A(x)=a_0 + a_1x+a_2x^2+\dotsi+a_{n-1}x^{n-1} A(x)=a0+a1x+a2x2++an1xn1

∵ 一 个 n 次 多 项 式 可 以 被 n + 1 个 点 唯 一 确 定 . \because 一个n次多项式可以被n+1个点唯一确定. nn+1.
∴ 将 w n 0  ⁣ ⋯ w n n − 1 代 入 可 以 确 定 该 多 项 式 . \therefore 将 w_n^0 \dotsi w_n^{n-1} 代入可以确定该多项式. wn0wnn1.

这里默认 n n n 2 2 2 的整数次幂, 所以 n − 1 n-1 n1 为奇数 .

  • 对于上方多项式 A ( x ) A(x) A(x), 将其 系数 按奇偶分开, 得 ↓ ↓
    A ( x ) = ( a 0 + a 2 ∗ x 2 +  ⁣ ⋯ + a n − 2 ∗ x n − 2 ) + ( a 1 ∗ x + a 3 ∗ x 3 +  ⁣ ⋯ + a n − 1 ∗ x n − 1 ) A(x) = (a_0+a_2*x^2+ \dotsi + a_{n-2}*x^{n-2})+(a_1*x+a_3*x^3+ \dotsi + a_{n-1}*x^{n-1}) A(x)=(a0+a2x2++an2xn2)+(a1x+a3x3++an1xn1)
    设 设
    A 1 ( x ) = a 0 + a 2 x + a 4 x 2 +  ⁣ ⋯ + a n − 2 x n 2 − 1   A 2 ( x ) = a 1 + a 3 x + a 5 x 2 +  ⁣ ⋯ + a n − 1 x n 2 − 1 A_1(x)=a_0+a_2x+a_4x^2+ \dotsi+a_{n-2}x^{\frac{n}{2}-1}\\ \ \\ A_2(x)=a_1+a_3x+a_5x^2+ \dotsi+a_{n-1}x^{\frac{n}{2}-1} A1(x)=a0+a2x+a4x2++an2x2n1 A2(x)=a1+a3x+a5x2++an1x2n1
    则 则
    A ( x ) = A 1 ( x 2 ) + x ∗ A 2 ( x 2 ) A(x)=A_1(x^2)+x*A_2(x^2) A(x)=A1(x2)+xA2(x2)

代 入   w n k      ( k < n 2 )   得 代入\ w_n^k\ \ \ \ (k < \frac{n}{2})\ 得  wnk    (k<2n) 
A ( w n k ) = A 1 ( w n 2 k ) + w n k A 2 ( w n 2 k ) = A 1 ( w n 2 k ) + w n k A 2 ( w n 2 k ) A(w_n^k) = A_1(w_n^{2k})+w_n^kA_2(w_n^{2k})=A_1(w_{\frac{n}{2}}^k)+w_n^kA_2(w_{\frac{n}{2}}^k) A(wnk)=A1(wn2k)+wnkA2(wn2k)=A1(w2nk)+wnkA2(w2nk)

代 入   w n k + n 2   得 代入\ w_n^{k+\frac{n}{2}}\ 得  wnk+2n 
A ( w n k + n 2 )   = A 1 ( w n 2 k + n ) + w n k + n 2 A 2 ( w n 2 k + n )   = A 1 ( w n 2 k ∗ w n n ) − w n k A 2 ( w n 2 k w n n )   = A 1 ( w n 2 k ) − w n k A 2 ( w n 2 k )   = A 1 ( w n 2 k ) − w n k A 2 ( w n 2 k ) A(w_n^{k+\frac{n}{2}})\\\ \\=A_1(w_n^{2k+n})+w_n^{k+\frac{n}{2}}A_2(w_n^{2k+n})\\ \ \\ =A_1(w_n^{2k}*w_n^n)-w_n^kA_2(w_n^{2k}w_n^n)\\ \ \\ =A_1(w_n^{2k})-w_n^kA_2(w_n^{2k}) \\ \ \\ =A_1(w_{\frac{n}{2}}^k)-w_n^kA_2(w_{\frac{n}{2}}^k) A(wnk+2n) =A1(wn2k+n)+wnk+2nA2(wn2k+n) =A1(wn2kwnn)wnkA2(wn2kwnn) =A1(wn2k)wnkA2(wn2k) =A1(w2nk)wnkA2(w2nk)

结 论 : 结论: :
  • A ( w n k ) = A 1 ( w n 2 k ) + w n k A 2 ( w n 2 k ) A(w_n^k) = A_1(w_{\frac{n}{2}}^k)+w_n^kA_2(w_{\frac{n}{2}}^k) A(wnk)=A1(w2nk)+wnkA2(w2nk)

  • A ( w n k + n 2 ) = A 1 ( w n 2 k ) − w n k A 2 ( w n 2 k ) A(w_n^{k+\frac{n}{2}})=A_1(w_{\frac{n}{2}}^k)-w_n^kA_2(w_{\frac{n}{2}}^k) A(wnk+2n)=A1(w2nk)wnkA2(w2nk)

可以观察到第二个式子与第一个式子的唯一区别就是正负号 .

根据上方式子分治处理出每个子项, 再向上合并, 时间复杂度 O ( N l o g N ) O(NlogN) O(NlogN) .


总 结 : 总结: :

F F T FFT FFT是先将多项式转换为 点值表示, 然后进行分治处理, 再转变为多项式的 O ( n l o g n ) O(nlogn) O(nlogn) 算法 .

推导过程:

  1. 把 系 数 按 奇 偶 分 开 把系数按奇偶分开
  2. 代入 单位根 .
  3. 得到 “分治向上递推式” .

  • F F T 的 实 现 FFT的实现 FFT

借用 这位大佬 的一个图,

在这里插入图片描述

将原序列进行二进制翻转的变换 .

r e v [ i ] = ( r e v [ i > > 1 ] > > 1 ) ∣ ( ( i & 1 ) < < b i t _ n u m − 1 ) rev[i] = (rev[i>>1]>>1) | ((i\&1) << bit\_num-1) rev[i]=(rev[i>>1]>>1)((i&1)<<bit_num1)

详解点击 这里 .


下面是 模板 代码 .

#include<bits/stdc++.h>

#define reg register

const int maxn = 1e6 + 5;
const double Pi = acos(-1);

struct complex{
        double x, y;
        complex(double x = 0, double y = 0):x(x), y(y) {}
} A[maxn<<2], B[maxn<<2];

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); }

int N, M;
int rev[maxn<<2];

void FFT(complex *F, short Opt){
        for(int i = 0; i < N; i ++)
                if(i < rev[i]) std::swap(F[i], F[rev[i]]);
        for(int p = 2; p <= N; p <<= 1){
                int len = p >> 1;
                complex tmp(cos(Pi/len), Opt*sin(Pi/len));
                for(int i = 0; i < N; i += p){
                        complex Buf(1, 0);
                        for(reg int k = i; k < i+len; k ++){
                                complex Temp = Buf * F[k+len];
                                F[k+len] = F[k] - Temp;
                                F[k] = F[k] + Temp;
                                Buf = Buf * tmp;
                        }
                }
        }
}

int main(){
        N = read(), M = read();
        for(int i = 0; i <= N; i ++) A[i].x = read();
        for(int i = 0; i <= M; i ++) B[i].x = read();
        int bit_num = 0;
        for(M += N, N = 1; N <= M; N <<= 1) bit_num ++;
        for(int i = 0; i < N; i ++) rev[i] = (rev[i>>1]>>1)|((i&1)?N>>1:0);
        // for(int i = 0; i < N; i ++) rev[i] = (rev[i>>1]>>1) | ((i&1) << bit_num-1);
        FFT(A, 1), FFT(B, 1);
        for(int i = 0; i < N; i ++) B[i] = A[i] * B[i];
        FFT(B, -1);
        for(reg int i = 0; i <= M; i ++) printf("%.0lf ", fabs(B[i].x/N));
        return 0;
}
  • F F T 的 应 用 FFT的应用 FFT

万 径 人 踪 灭 万径人踪灭

力 力

礼 物 礼物


  • F F T   魔 改 − > N T T FFT\ 魔改-> NTT FFT >NTT

  1. 将单位根 w n w_n wn 替换为原根 g m o d − 1 l e n g^{\frac{mod-1}{len}} glenmod1
  2. 最后乘的是 T _ l e n T\_len T_len 的逆元 .

其中 g g g 在 模数 998244353 998244353 998244353下取 3 3 3 .

void FFT(complex *F, int opt){
        for(reg int i = 0; i < FFT_Len; i ++)
                if(i < rev[i]) std::swap(F[i], F[rev[i]]);
        for(reg int p = 2; p <= FFT_Len; p <<= 1){
                int half = p >> 1;
                complex t = complex(cos(Pi/half), opt*sin(Pi/half));
                for(reg int i = 0; i < FFT_Len; i += p){
                        complex buf = complex(1, 0);
                        for(reg int k = i; k < i+half; k ++){
                                complex Tmp = buf * F[k + half];
                                F[k + half] = F[k] - Tmp;
                                F[k] = F[k] + Tmp;
                                buf = buf * t;
                        }
                }
        }
}

void NTT(int *f, int opt){
        for(reg int i = 0; i < T_len; i ++)
                if(i < rev[i]) std::swap(f[i], f[rev[i]]);
        for(reg int p = 2; p <= T_len; p <<= 1){
                int half = p >> 1;
                int wn = Ksm(3, (mod-1)/p);
                if(opt == -1) wn = Ksm(wn, mod-2);
                for(reg int i = 0; i < T_len ; i += p){
                        int buf = 1;
                        for(reg int k = i; k < i+half; k ++){
                                int Tmp_1 = 1ll*buf*f[k+half] % mod;
                                f[k+half] = (f[k] - Tmp_1 + mod) % mod;
                                f[k] = (f[k] + Tmp_1) % mod;
                                buf = 1ll*buf*wn % mod;
                        }
                }
        }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值