[学习笔记] 多项式全家桶 学习笔记

第一章 FFT

0x00 记号说明

全部采用 F [ i ] F[i] F[i] 表示多项式第 i i i 次项系数。(数组可能是下标)

统一使用 ∗ * 作为卷积。

0x10 前置知识

来自初三的 SMT:本章节写于初一升初二暑假。部分内容垃圾就原谅我吧。

我觉得啊,初一下应该就要熟练任意模数 NTT ,不然怎么做初二初三的多项式(狗头)——STJqwq,初一

我 cnm 老子没说过这句话——SmallTualatin,初三

FFT 的思想是多项式世界大门的钥匙,有了它,毒瘤 新的世界将对你们敞开。

前置知识:

  • 函数和多项式,初中的定义
  • 一点点复数的知识,知道 i = − 1 i=\sqrt{-1} i=1 这种东西 ,FFT要用
  • 一些奇怪的同余知识(至少要会求逆元),NTT要用,任意模数NTT也要用
  • 有手,有脑子

复数类的具体实现:

定义一个复数为 a + b i a+bi a+bi i i i − 1 \sqrt{-1} 1
加法: a + b i + c + d i = ( a + c ) + ( b + d ) i a+bi+c+di=(a+c)+(b+d)i a+bi+c+di=(a+c)+(b+d)i
减法:同上,系数改成 − 1 -1 1
乘法: ( a + b i ) ( c + d i ) = a c + a d i + b c i + b d i 2 = ( a c − b d ) + ( a d + b c ) i (a+bi)(c+di)=ac+adi+bci+bdi^2=(ac-bd)+(ad+bc)i (a+bi)(c+di)=ac+adi+bci+bdi2=(acbd)+(ad+bc)i
除法:其实是可以的,但是这里不需要。

下列实现了一个比较简洁的复数类。

struct cp{
   
	double x,y;
	friend cp operator +(cp a,cp b){
   
		return {
   a.x+b.x,a.y+b.y};
	}friend cp operator -(cp a,cp b){
   
		return {
   a.x-b.x,a.y-b.y};
	}friend cp operator *(cp a,cp b){
   
		return {
   a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
	}
};

0x11 算法流程

(1)两个系数序列点值化->(2)每个点值乘起来->(3)点值序列系数化
考虑如何 点值化 系数序列 和 如何 系数化 点值序列
给个样例手模一下,1 22 3 1

然后我们取 − 1 -1 1 0 0 0 1 1 1 点上的答案:
f ( − 1 ) = − 1 , f ( 0 ) = 1 , f ( 1 ) = 3 f(-1)=-1,f(0)=1,f(1)=3 f(1)=1,f(0)=1,f(1)=3 g ( − 1 ) = 0 , g ( 0 ) = 2 , g ( 1 ) = 6 g(-1)=0,g(0)=2,g(1)=6 g(1)=0,g(0)=2,g(1)=6
所以设 h ( x ) = f ( x ) × g ( x ) h(x)=f(x)\times g(x) h(x)=f(x)×g(x),那么 h ( − 1 ) = − 1 × 0 = 0 , h ( 0 ) = 1 × 2 = 2 , h ( 1 ) = 3 × 6 = 18 h(-1)=-1\times 0=0,h(0)=1\times 2=2,h(1)=3\times 6=18 h(1)=1×0=0,h(0)=1×2=2,h(1)=3×6=18

发现函数图像是对的!
手模样例,最后的结果为 2 7 7 2

证明:点值表示 f ( x ) = ∑ i = 0 n f [ i ] x i f(x)=\sum\limits_{i=0}^{n} f[i]x^i f(x)=i=0nf[i]xi g ( x ) = ∑ i = 0 n g [ i ] x i g(x)=\sum\limits_{i=0}^{n} g[i]x^i g(x)=i=0ng[i]xi

h ( x ) h(x) h(x) 相当于每一项都枚举乘起来,那么 f ( x ) × g ( x ) = ∑ i = 0 n f [ i ] x i × ∑ j = 0 n g [ j ] x j f(x)\times g(x)=\sum\limits_{i=0}^{n} f[i]x^i \times \sum\limits_{j=0}^{n} g[j]x^j f(x)×g(x)=i=0nf[i]xi×j=0ng[j]xj
g ( x ) = ∑ i = 0 n f [ i ] ∑ j = 0 n g [ j ] x i + j g(x)=\sum\limits_{i=0}^{n} f[i]\sum\limits_{j=0}^{n} g[j]x^{i+j} g(x)=i=0nf[i]j=0ng[j]xi+j ,就是多项式乘法的定义。
DFT 就是求出这个点值转系数和系数转点值。然而暴力太慢,于是考虑从 O ( n 2 ) O(n^2) O(n2) 优化成 O ( n log ⁡ n ) O(n\log n) O(nlogn)

0x12 DFT的分治优化

FFT 的分治流程:先把这个序列通过补 0 0 0 扩充到 2 2 2 的整数幂次方。即 n 为 2 m − 1 2^m-1 2m1 的形式,其中 m m m 为最小的 2 m > n 2^m>n 2m>n 的数。
然后
把序列按照奇偶分治
f ( x ) = f [ 0 ] + f [ 1 ] x + f [ 2 ] x 2 + . . . + f [ n ] x n f(x)=f[0]+f[1]x+f[2]x^2+...+f[n]x^n f(x)=f[0]+f[1]x+f[2]x2+...+f[n]xn
那么拆成两半, f ( x ) = ( f [ 0 ] + f [ 2 ] x 2 + . . . ) + ( f [ 1 ] x + f [ 3 ] x 3 + . . . ) f(x)=(f[0]+f[2]x^2+...)+(f[1]x+f[3]x^3+...) f(x)=(f[0]+f[2]x2+...)+(f[1]x+f[3]x3+...)
于是右边柿子提出一个 x x x, f ( x ) = ( f [ 0 ] + f [ 2 ] x 2 + . . . ) + x ( f [ 1 ] + f [ 3 ] x 2 + . . . ) f(x)=(f[0]+f[2]x^2+...)+x(f[1]+f[3]x^2+...) f(x)=(f[0]+f[2]x2+...)+x(f[1]+f[3]x2+...)
然后发现两边的柿子中带入的数是 x 2 x^2 x2 ,于是继续递归下去
F ( x ) = F L ( x 2 ) + F R ( x 2 ) x F(x)=FL(x^2)+FR(x^2)x F(x)=FL(x2)+FR(x2)x

0x13 带入什么 x x x 合适

因为代入普通的 x x x 没有什么特殊性质,所以考虑所有 x n = 1 x^n=1 xn=1 x x x
大眼观察法,我们似乎只有 − 1 -1 1 1 1 1 ,但是引入复数系之后,我们可以找到 n n n 个。
在这里插入图片描述
把复数域作为向量,搞到平面直角坐标系上。 ( x , y ) (x,y) (x,y) 点就代表 x + y i x+yi x+yi 这样一个复数。
在这里插入图片描述
如果对于 a 4 = 1 a^4=1 a4=1 的解 a a a ,那么就有 1 , − 1 , i , − i 1,-1,i,-i 1,1,i,i 都可以满足这个答案。
于是得出这么一个结论:单位圆上 n n n 等份,每个被切割的点即为 a n = 1 a^n=1 an=1 的一个解。这个 n n n 等份可以使用 三角函数 求出。

一号单位根的位置: ( c o s ( 2 π n ) , s i n ( 2 π n ) ) (cos(\dfrac{2\pi}{n}),sin(\dfrac{2\pi}{n})) (cos(n2π),sin(n2π)) 。它被定义成 ω n 1 \omega_{n}^{1} ωn1

然后有一个性质: ω n i = ( ω n 1 ) i \omega_{n}^i=(\omega_{n}^1)^i ωni=(ωn1)i 。这个显而易见,计算单位复根,弧度就是它的多少倍,所以是多少次方。
还有一个性质, ω 2 n 2 i = ω n i \omega_{2n}^{2i}=\omega_{n}^i ω2n2i=ωni 。这个也显然。
还有一个性质, ω n 0 = 1 , ω n i = ω n i % n \omega_{n}^0=1,\omega_{n}^{i}=\omega_{n}^{i\% n} ωn0=1,ωni=ωni%n 。因为一个圆上所有点的排列是循环的。

一个性质: ω 2 n k + n = − ω 2 n k \omega_{2n}^{k+n}=-\omega_{2n}^{k} ω2nk+n=ω2nk ,这个按照图形推导即可,就是圆上与它相对的点嘛。

0x14 FFT 最后的证明

我们接着上面的证明:

F ( x ) = F L ( x 2 ) + F R ( x 2 ) x F(x)=FL(x^2)+FR(x^2)x F(x)=FL(x2)+FR(x2)x

考虑代入单位根,(每个 k ≤ n / 2 k\le n/2 kn/2
D F T ( F ( ω n k ) ) = D F T ( F L ( ( ω n k ) 2 ) ) + ω n k D F T ( F R ( ( ω n k ) 2 ) ) D F T ( F ( ω n k ) ) = D F T ( F L ( ω n 2 k ) ) + ω n k D F T ( F R ( ω n 2 k ) ) D F T ( F ( ω n k ) ) = D F T ( F L ( ω n / 2 k ) ) + ω n k D F T ( F R ( ω n / 2 k ) ) DFT(F(\omega_{n}^{k}))=DFT(FL((\omega_{n}^{k})^2))+\omega_{n}^{k}DFT(FR((\omega_{n}^{k})^2))\\ DFT(F(\omega_{n}^{k}))=DFT(FL(\omega_{n}^{2k}))+\omega_{n}^{k}DFT(FR(\omega_{n}^{2k}))\\ DFT(F(\omega_{n}^{k}))=DFT(FL(\omega_{n/2}^{k}))+\omega_{n}^{k}DFT(FR(\omega_{n/2}^{k})) DFT(F(ωnk))=DFT(FL((ωnk)2))+ωnkDFT(FR((ωnk)2))DFT(F(ωnk))=DFT(FL(ωn2k))+ωnkDFT(FR(ωn2k))DFT(F(ωnk))=DFT(FL(ωn/2k))+ωnkDFT(FR(ωn/2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值