天上掉下来的FFT

FFT

本文学习借鉴 Link 董晓算法

说实话董老师讲的太好了

前言

闲来无事,点了一下随机跳题。

LUOGU 4461 [CQOI2018] 九连环

读完题随便一写, O ( n ) O(n) O(n) 的转移(当时很激动,毕竟以为秒了紫题)。反手一交 30 p t s 30pts 30pts 仔细一看,这题居然没有让去模!?!(开始发癫。

FFT 前置芝士

虚数的意义

我们将坐标系上的点可以这样理解:

n n n 看作实部 m m m 看作虚部,即点 A = n + i m A = n + im A=n+im

呢我们就可以用半径和角度表示一个圆上的点。

如点 A = cos ⁡ θ ⋅ r + i ⋅ sin ⁡ θ ⋅ r A = \cos \theta \cdot r + i \cdot \sin \theta \cdot r A=cosθr+isinθr

则利用 π \pi π 来表示角度,钦定将圆分成 n n n 份这个角度占 k k k 份,再钦定 r = 1 r = 1 r=1 就出现了一个神奇的表示:

单位根 ω n k = cos ⁡ 2 π k n + i ⋅ sin ⁡ 2 π k n \omega ^ k _ n = \cos \frac {2 \pi k} {n} + i \cdot \sin \frac {2 \pi k}{n} ωnk=cosn2πk+isinn2πk

其有一些神奇且具象的性质:

周期性 : ω n k = ω n k + n \omega ^ {k} _ {n} = \omega ^ {k + n} _ {n} ωnk=ωnk+n

很好理解就是转一圈回到原点.

对称性 : ω n k + n 2 = − ω n k \omega ^ {k + \frac{n}{2}} _ {n} = - \omega ^ {k} _ {n} ωnk+2n=ωnk

形如上图点 C 和点 D,转了 180 度相当于原数取反.

折半性 : ω 2 n 2 k = ω n k \omega ^ {2k} _ {2n} = \omega ^ {k} _ {n} ω2n2k=ωnk

相当于分子分母化简,也很好理解 你在分成 8 份时取 4 份和在 4 份中去 2 份意义相同.

虚数乘

A = a 1 + i ⋅ a 2 , B = b 1 + i ⋅ b 2 A = a_1 + i \cdot a_2 , B = b_1 + i \cdot b_2 A=a1+ia2,B=b1+ib2

A × B = ( a 1 + i ⋅ a 2 ) × ( b 1 + i ⋅ b 2 ) A \times B = ( a_1 + i \cdot a_2 ) \times(b_1 + i \cdot b_2) A×B=(a1+ia2)×(b1+ib2)

= a 1 b 1 + i 2 a 2 b 2 + i ( a 2 b 1 + a 1 b 2 ) = a_1b_1 + i^2a_2b_2 + i(a_2b_1 + a_1b_2) =a1b1+i2a2b2+i(a2b1+a1b2)

= a 1 b 1 − a 2 b 2 + i ( a 2 b 1 + a 1 b 2 ) = a_1b_1 - a_2b_2 + i(a_2b_1 + a_1b_2) =a1b1a2b2+i(a2b1+a1b2)

开始正题

众所周知 , 一个 n n n 阶多项式可以用 n n n 个点来唯一确定.

对于长度为 n n n 的多项式

A ( x ) = a 1 + a 2 x + a 3 x 2 ⋯ a n + 1 x n A(x) = a_1 + a_2x + a_3x^2 \cdots a_{n+ 1}x^n A(x)=a1+a2x+a3x2an+1xn

我们可以间其奇数次幂和偶数次幂分离(别问为什么这样做,我感觉 FFT 的思路就是天上掉下来的)

奇数次幂 : ( a 1 x + a 3 x 3 ⋯ a n − 1 x n − 2 ) = ( a 2 + a 4 x 2 ⋯ a n x n ) ⋅ x (a_1x + a_3x^3 \cdots a_{n - 1}x^{n - 2}) = (a_2 + a_4x^2 \cdots a_{n}x^{n}) \cdot x (a1x+a3x3an1xn2)=(a2+a4x2anxn)x

偶数次幂 : ( a 0 + a 2 x 2 ⋯ a n − 2 x n − 2 ) (a_0 + a_2x^2 \cdots a_{n - 2}x^{n - 2}) (a0+a2x2an2xn2)

设:

A 1 ( x ) = ( a 0 + a 2 x 2 ⋯ a n − 2 x n 2 − 1 ) A_1(x) = (a_0 + a_2x^2 \cdots a_{n - 2}x^{\frac n 2 - 1}) A1(x)=(a0+a2x2an2x2n1)

A 2 ( x ) = ( a 1 + a 3 x 2 ⋯ a n − 1 x n 2 − 1 ) A_2(x) = (a_1 + a_3x^2 \cdots a_{n - 1}x^{\frac n 2 -1}) A2(x)=(a1+a3x2an1x2n1)

A ( x ) = A 1 ( x 2 ) + A 2 ( x 2 ) ⋅ x A(x) = A_1(x ^ 2) + A_2(x ^ 2) \cdot x A(x)=A1(x2)+A2(x2)x

用前面的单位根往里带(评价为天上掉下来的)

图片来自董老师 Link 董晓算法

发现如果 n = 2 k n = 2 ^ k n=2k 就可以直接二分到底,所有我们钦定 n = 2 k n = 2 ^ k n=2k .

可以直接递归到底然后再反推回来.

我们就可以得到 n 个点

求出 多项式 A 和 B 把每个点乘起来,再把单位根的倒数带入将点值转话为 z i = a i ⋅ n z_i = a_i \cdot n zi=ain

图片来自董老师 Link 董晓算法

所有 a i = z i n a_i = \frac {z_i} n ai=nzi 就得到答案了!

优化

递归显然是不优雅的

我们观察最终搜索到的序列,

图片来自董老师 Link 董晓算法

观察发现每个数字的结果其实就是将原数的二进制倒过来

称之为蝴蝶变化.

这时候 zxc 大佬就要开始发癫了

如何求呢?

观察发现 f[i] = f[i / 2] / 2 + [i & 1] * n / 2;

所有我们就可以 O ( n ) O(n) O(n) 推出变化 O ( n log ⁡ n ) O(n \log n) O(nlogn) 得到答案.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值