前言
http://www.cnblogs.com/stxy-ferryman/p/8507434.html
课上zrf 大佬讲FFT,讲了一半,本蒟蒻莫名奇妙突然开始开始思考人生,回过神来发现自己早已掉(G)线(G),感谢xhkxhk帮我恶补一发。看了xhk同学的博客,经其讲解才搞懂,下面我用我自己的想法仔细写写对FFT的理解,如有错误,欢迎指正。
整体思路是以算导为基础的,so~~~
PART1:多项式
多项式这个东西,算法导论上是这么写的
然而这只是第一个定义,要求两个它的值复杂度显然是 Θ(n2) Θ ( n 2 ) 的,那该咋整呢??于是我们来合并一下同类项,变形为这个:
这样就可以在 Θ(n) Θ ( n ) 的复杂度之内搞定了(从里到外逐项展开,每算一项乘以个 x x ,把两重循环放在一起算)。
这个就叫做霍纳法则,名字也是个吓唬人的东西(和那个勾股定理一样,可以有不同的说法,比如:范数或欧几里得范数什么的)
虽说这玩意挺高大上,但遇到多项式乘法要表示乘积的系数就麻烦了。
PART2:卷积
卷积!吓人吧!吓死你!网络上讲的糊里糊涂的,我用两种不同的方式来讲清楚它。
法一:线性代数
-
设向量a=⎡⎣⎢⎢⎢⎢⎢⎢⎢a1a2a3⋮an⎤⎦⎥⎥⎥⎥⎥⎥⎥向量b=⎡⎣⎢⎢⎢⎢⎢⎢⎢b1b2b3⋮bm⎤⎦⎥⎥⎥⎥⎥⎥⎥
设
向
量
a
=
[
a
1
a
2
a
3
⋮
a
n
]
向
量
b
=
[
b
1
b
2
b
3
⋮
b
m
]
a⋅b┬=⎡⎣⎢⎢⎢⎢⎢⎢⎢a1b1a2b1a3b1⋮anb1a1b2a2b2a3b2⋮anb2a1b3a2b3a3b3⋮anb3⋯⋯⋯⋱⋯a1bna2bna3bn⋮anbn⎤⎦⎥⎥⎥⎥⎥⎥⎥ a · b ┬ = [ a 1 b 1 a 1 b 2 a 1 b 3 ⋯ a 1 b n a 2 b 1 a 2 b 2 a 2 b 3 ⋯ a 2 b n a 3 b 1 a 3 b 2 a 3 b 3 ⋯ a 3 b n ⋮ ⋮ ⋮ ⋱ ⋮ a n b 1 a n b 2 a n b 3 ⋯ a n b n ]然后,我们把斜对角的数值分别加起来,按顺序排列便得到了卷积序列,按顺序分别乘上 x x 对应的幂即可。
-
设向量a=⎡⎣⎢⎢⎢⎢⎢⎢⎢a1a2a3⋮an⎤⎦⎥⎥⎥⎥⎥⎥⎥向量b=⎡⎣⎢⎢⎢⎢⎢⎢⎢b1b2b3⋮bm⎤⎦⎥⎥⎥⎥⎥⎥⎥
设
向
量
a
=
[
a
1
a
2
a
3
⋮
a
n
]
向
量
b
=
[
b
1
b
2
b
3
⋮
b
m
]
法二:列竖式
- 这种方法较前一种就好理解多了,而且十分直观。我们拿两个式子B(x)=x3+5x+2 B ( x ) = x 3 + 5 x + 2那么∗2x52x5++4x54x5++10x40x410x4+++2x3x34x320x3x325x3+++++4x20x28x20x28x2+++++0x5x0x5x5x++++1222 2 x 3 + 4 x 2 + 0 x + 1 ∗ x 3 + 0 x 2 + 5 x + 2 4 x 3 + 8 x 2 + 0 x + 2 10 x 4 + 20 x 3 + 0 x 2 + 5 x 2 x 5 + 4 x 5 + 0 x 4 + x 3 2 x 5 + 4 x 5 + 10 x 4 + 25 x 3 + 8 x 2 + 5 x + 2
所以我们要求的C(x)=A(x)⋅B(x)=2x5+4x5+10x4+25x3+8x2+5x+2 C ( x ) = A ( x ) · B ( x ) = 2 x 5 + 4 x 5 + 10 x 4 + 25 x 3 + 8 x 2 + 5 x + 2
这种算法显然复杂度是 Θ(n2) Θ ( n 2 ) 的,要是数据 n,m≤10000 n , m ≤ 10000 ,就GG了,于是我们就有了part3。
- 这种方法较前一种就好理解多了,而且十分直观。我们拿两个式子
PART3:点值表示
点值表示,这里需要注意!!!
我们发现直接乘要用
Θ(n2)
Θ
(
n
2
)
的时间,不够优越,点值表示就是一个把
Θ(n2)
Θ
(
n
2
)
的复杂度降至
Θ(n)
Θ
(
n
)
的一种方法。
首先,我们需要先糊出这么一个有意思的结论:一个多项式
A(x)
A
(
x
)
与一个集合
{(x0,A(x0)),(x1,A(x1)),(x2,A(x2)),...,(xn−1,A(xn−1))}
{
(
x
0
,
A
(
x
0
)
)
,
(
x
1
,
A
(
x
1
)
)
,
(
x
2
,
A
(
x
2
)
)
,
.
.
.
,
(
x
n
−
1
,
A
(
x
n
−
1
)
)
}
可以构成一个严格的一一映射。点值表示就是将
n−1
n
−
1
次多项式
A(x)
A
(
x
)
表示成该多项式所表示的函数上的
n
n
个不重合的点的表示法。
(当然你想用998244353或是1e9+7也没人拦你)。
(
当
然
你
想
用
998244353
或
是
1
e
9
+
7
也
没
人
拦
你
)
。
例如:A(x)=x2+1就能表示成集合{(0,1),(1,2),(2,5)}的形式。
例
如
:
A
(
x
)
=
x
2
+
1
就
能
表
示
成
集
合
{
(
0
,
1
)
,
(
1
,
2
)
,
(
2
,
5
)
}
的
形
式
。
那么如何证明呢???似乎有点难抓头绪,但我们还是得试试。
不过,在这之前我要先引入一个新的概念,叫范德蒙德矩阵(这种高大上的名字都是吓唬人用的,不用管它叫什么<就像化学里的盖斯定律和物理中的动能定理一样显然>)
证法:数学归纳法
知识铺垫:行列式性质 知 识 铺 垫 : 行 列 式 性 质
1.如果矩阵A中某行或某列为0,则det(A)=0 1. 如 果 矩 阵 A 中 某 行 或 某 列 为 0 , 则 d e t ( A ) = 0
2.当将矩阵A中某行或某列每个元素乘以λ后,det(A)相应乘以λ 2. 当 将 矩 阵 A 中 某 行 或 某 列 每 个 元 素 乘 以 λ 后 , d e t ( A ) 相 应 乘 以 λ
3.当将矩阵A中某行(列)每个元素加到另一行(列)上,det(A)不变 3. 当 将 矩 阵 A 中 某 行 ( 列 ) 每 个 元 素 加 到 另 一 行 ( 列 ) 上 , d e t ( A ) 不 变
4.det(A)=det(A┬) 4. d e t ( A ) = d e t ( A ┬ )
5.交换A的任意两行或两列,行列式改变正负号 5. 交 换 A 的 任 意 两 行 或 两 列 , 行 列 式 改 变 正 负 号
6.det(AB)=det(A)det(B) 6. d e t ( A B ) = d e t ( A ) d e t ( B )
有了前置知识,我们就可以开始证明啦!
第一步
第二步
很妙。但接着这一步要看仔细了!!!我们把第2至n行中,第i行减去x_0倍的第i-1行。注意:从下往上处理:
好累啊,但是我们继续。将此多项式展开,你会发现:由于第一列除了第一项是1以外,其它全都是0,所以展开之后只留 D(1,1) D ( 1 , 1 ) 及其代数余子式,别的都化成0了。于是乎我们展开可以得到这么个东西:
好看多了吧!接着,我们再用知识点2,可以将每一列的公因数都提出来,我们就得到了这个:
再用知识点4(我似乎发现前面根本不需要转置这一步233,但是我懒得改了,假装我不知道(逃) 再 用 知 识 点 4 ( 我 似 乎 发 现 前 面 根 本 不 需 要 转 置 这 一 步 233 , 但 是 我 懒 得 改 了 , 假 装 我 不 知 道 ( 逃 )
呼~~~~终于证完了!!!!!
那么下一步我们就继续讲插值(把点值表达改为多项式)吧。
等等,让我们再来看一个东西:拉格朗日公式
这个公式证明有两步
一:存在的唯一性确认
其实这步证好,我们要求的东西也就搞定了。
这时我们应该先把别的杂念全部抛开,不要和上面的东西混淆了,否则越看越糊涂
好,我们准备开始。
先设一个函数f(x),f(xj)=yj(j=0,1,⋯,n)再设一个多项式
先
设
一
个
函
数
f
(
x
)
,
f
(
x
j
)
=
y
j
(
j
=
0
,
1
,
⋯
,
n
)
再
设
一
个
多
项
式
仔细观察该式,我们可以发现,该式相当于两两不同的 xi x i 和 xj x j 的差的乘积
由于当 i≠j i ≠ j 时 xi≠xj x i ≠ x j 所以该式的值不为0。
然后我们需要一个结论:若n*n的矩阵是奇异的(无逆矩阵的),当且仅当该矩阵的行列式值为零
然后
未完待续。。。。
忽略下面。。。
方法:线性代数
又是线性代数(
搞得好像拉格朗日插值法不是线性代数似的
搞
得
好
像
拉
格
朗
日
插
值
法
不
是
线
性
代
数
似
的
),不过这线性代数可比拉格朗日公式通俗易懂多了(那必须的)