FFT和NTT真是噩梦呢

既然被FFT和NTT坑够了,坑一下其他的人也未尝不可呢


前置知识

  • 多项式基础知识
  • 矩阵基础知识(之后会一直用矩阵表达)
  • FFT:复数基础知识
  • NTT:模运算基础知识

单位根介绍

设有一个数a,使得an=1,其中n为满足an=1的最小正整数

满足条件的a有哪些呢?

  • 复数域上的(cos(2π/n)+sin(2π/n)*i)(一般用ωn表示)
  • 模运算中的原根g(mod n+1)

更宽泛地说,只要在一个集合中定义了加法和乘法,而且二者满足:

  • 存在元素“0”,使得加上“0”的结果不变
  • 存在元素“1”,使得乘以“1”的结果不变
  • 加法/乘法结合律
  • 加法/乘法交换律
  • 乘法分配律
  • 每个非0数都能做除数
  • 每个数都能做加减乘数和被除数
  • 加减乘除后的运算结果也在这个集合中

(这些基本上是小学学的吧,除了最后一点之外,其他都是废话)

那么里面满足an=1的数都是我们可以讨论的数

这样说,这些数也是可以满足要求的:

  • 复数域上ωn的p次方
  • 模运算中的原根g(mod n+1)的p次方

这里的a就是我们要找的单位根

好,这下我们来探讨一下FFT&NTT


FFT&NTT的数学推导

首先,我们要知道这两个是干什么的

FFT和NTT都是DFT的分治法下的优化

而DFT则是将多项式的系数表达(就是“满足f(x)=a+bx+cx2+dx3……的多项式”)变为点值表达(就是“经过(a,a'),(b,b'),(c,c')……的多项式”)的暴力算法

用矩阵表达就是:

很明显,DFT的时间复杂度为Θ(n2)的,这时单位元素的作用就体现出来了

我们把单位元素b及b的幂代替xi,其中b所对应的n和矩阵的边长相等,那么可以得到:

看上去就是换了个表示方法,但是变一下形就能分治了:

没看出来?再变一下形试试:

是不是猛然发现我们有两个相同的矩阵了?把相同的矩阵拿出来,去掉0看看:

这不就是把b2代进去的DFT式子吗,通过前面的叙述我们可以知道b2也是单位元素,那么只要一开始的n是2的幂,我们就可以分治了是不是?

事情没有这么简单,细心的可能会发现,我这里挖了一个大坑:前面那个矩阵不是一个方阵,也就是说,前面那个矩阵等于:

但是通过单位元素的定义可以知道,(b2)n/2=1,也就是说有:

下面的半边竟然和上面的一样!忽略掉下面重复的半边矩阵,转移矩阵又变成了一个方阵,我们又可以开始分治了

知道了怎么分治计算其中一个矩阵,我们再看一下另外一个矩阵

另外一个矩阵是对角矩阵,可以在更快的Θ(n)内计算完成,但是我们想要做得更好(卡一卡常),那又怎么办呢?

这时我们可以发现,既然bn=1,n又是2的幂,那么就有bn/2=-1,也就是说:

我们只要后面半边转移时用减号代替加号,而不需要再计算后面半边的幂了,常数减半

到了这一步,基本的FFT&NTT框架就到这里了


IFFT&INTT的变化

说了这么多,把系数表达变成点值表达又有什么用呢?对广大OIer来说当然是加快多项式乘法了

对系数表达式暴力相乘当然是要Θ(n2)的,但是点值表达式就只要Θ(n)了:

但是又怎么把点值表达变回平常的系数表达呢?这就要用到一个公式了(只要记,不用证)

这就给我们了一个IFFT&INTT的方法:把这个新的矩阵和系数再乘回去,我们熟悉的系数表达就回来了

不仅如此,既然b是单位元素,那么b-1就也是单位元素,恩……IFFT&INTT干脆就可以用FFT&NTT的代码嘛


卡常优化

DFT&IDFT的优化介绍完毕了,但是还是很慢,那有什么办法卡常呢?

递归转倍增

我们可以发现,每次分治的时候,原多项式的系数都会移动到不同的矩阵,而且系数移动和计算可以分离,可不可以先移动,再计算呢?

当然!分析之后可以发现,如果把序号为偶数的向量放在序号为奇数的向量前面,那么原来位置为p的系数会移动到rev(p)处,用图来说就是:

(用的是n=16时的例子,因为实在不好表示)

那么我们可以先移动系数,再从下向上倍增地计算,那么就能优化常数了

代码(摘自洛谷日报):

for(int i=;i<n;i++)
r[i]=(r[i>>]>>)|((i&)?n>>:);

多项式乘法FFT的“三次变两次”优化

当用FFT计算实系数多项式乘法时,我们可以用这样一个公式快速计算结果:

这样我们就可以把两个多项式相乘变成单个多项式的平方,因此可以偷懒少算一次FFT


参考资料

洛谷日报:https://www.luogu.org/blog/command-block/fft-xue-xi-bi-ji

PS:这里只写了其数学解释,加强理解,并不会对代码实现进行深究


2019/10/10更新

忽然发现,这个证明改一改可以变为任意长度的快速离散傅里叶变换的证明,只要把2n换成an就可以了,这样就不用做把531441=312扩充为1048576=220这种极其不划算的事了,时间复杂度和原来的应该差不多(似乎并没有什么用的样子)

——会某人

FFT&NTT数学解释的更多相关文章

  1. [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)

    目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...

  2. FFT/NTT/MTT学习笔记

    FFT/NTT/MTT Tags:数学 作业部落 评论地址 前言 这是网上的优秀博客 并不建议初学者看我的博客,因为我也不是很了解FFT的具体原理 一.概述 两个多项式相乘,不用\(N^2\),通过\ ...

  3. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ

    众所周知,tzc 在 2019 年(12 月 31 日)就第一次开始接触多项式相关算法,可到 2021 年(1 月 1 日)才开始写这篇 blog. 感觉自己开了个大坑( 多项式 多项式乘法 好吧这个 ...

  4. FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅲ

    第三波,走起~~ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅰ FFT/NTT复习笔记&多项式&生成函数学习笔记Ⅱ 单位根反演 今天打多校时 1002 被卡科技了 ...

  5. FFT \ NTT总结(多项式的构造方法)

    前言.FFT  NTT 算法 网上有很多,这里不再赘述. 模板见我的代码库: FFT:戳我 NTT:戳我 正经向:FFT题目解题思路 \(FFT\)这个玩意不可能直接裸考的..... 其实一般\(FF ...

  6. FFT&NTT总结

    FFT&NTT总结 一些概念 \(DFT:\)离散傅里叶变换\(\rightarrow O(n^2)\)计算多项式卷积 \(FFT:\)快速傅里叶变换\(\rightarrow O(nlogn ...

  7. MACD 的数学解释

    目录 MACD 的数学解释 MACD 的一般定义 引入延迟算子 Taylor 展开 权重分析 共振? MACD 的数学解释 MACD 的一般定义 \[ \begin{align*} DIF & ...

  8. 快速构造FFT/NTT

    @(学习笔记)[FFT, NTT] 问题概述 给出两个次数为\(n\)的多项式\(A\)和\(B\), 要求在\(O(n \log n)\)内求出它们的卷积, 即对于结果\(C\)的每一项, 都有\[ ...

  9. FFT/NTT模板 既 HDU1402 A * B Problem Plus

    @(学习笔记)[FFT, NTT] Problem Description Calculate A * B. Input Each line will contain two integers A a ...

随机推荐

  1. Linux grep常用命令

    在一个文件中同时查找多个字符串: 并集语法: grep -e 'pattern1 -e 'pattern2 file 或集语法: 1.grep -E 'pattern1|pattern2' file ...

  2. JSTL报错Unable to read TLD "META-INF/c.tld" from JAR file "file.............................

    **********菜鸟的福利^_^************ 我用的是jstl-1.2.jar,网上很多说法是删掉工程lib下面的两个jar包,那是之前的老版本,现在整合成一个了. 我出现这个问题的原 ...

  3. vue 实现模糊检索,并根据其他字符的首字母顺序排列

    昨天让我做一个功能,实现一个模糊检索,我就想,那做呗,然后开始正常的开发 代码如下: HTML VUE 因为是实时的,所以写了将逻辑写到了watch中 五分钟搞定.   我以为这就完了,然而产品的需求 ...

  4. Cheatsheet: 2019 03.01 ~ 04.30

    Golang How To Install Go and Set Up a Local Programming Environment on macOS Build A Go API 40+ prac ...

  5. ASE Alpha Sprint - backend scrum 7

    本次scrum于2019.11.12在sky garden进行,持续30分钟. 参与人: Zhikai Chen, Jia Ning, Hao Wang 请假: Xin Kang, Lihao Ran ...

  6. Java代码乱象!

    文章转载自公众号  阿里巴巴中间件 , 作者 陈昌毅 导读 查尔斯·狄更斯在<双城记>中写道:“这是一个最好的时代,也是一个最坏的时代.” 移动互联网的快速发展,出现了许多新机遇,很多创业 ...

  7. 微信小程序(16)-- bindtap,catchtap事件绑定的区别

    bindtap,catchtap事件绑定的区别,这里就涉及冒泡事件了.bind事件绑定不会阻止冒泡事件向上冒泡,catch事件绑定可以阻止冒泡事件向上冒泡. logs.wxml <view cl ...

  8. Java并发(具体实例)—— 构建高效且可伸缩的结果缓存

    这个例子来自<Java并发编程实战>第五章.本文将开发一个高效且可伸缩的缓存,文章首先从最简单的HashMap开始构建,然后分析它的并发缺陷,并一步一步修复. hashMap版本     ...

  9. token理解

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  10. PyQt5界面上调用subprocess.Popen会闪命令窗口的问题

    最近再做一个界面开发,主要实现的点击一个按钮,会执行adb安装应用程序的功能,在调试阶段一切都正常,但打包成一个exe安装程序,安装之后运行,点击按钮会闪一下adb的命令窗口 先列出subproces ...