生成函数
泰勒多项式
对于函数f f f ,设他在点x 0 x_0 x 0 处存在直到n n n 阶的导数,构造一个n n n 次多项式:
T n ( x ) = f ( x 0 ) + f ′ ( x 0 ) 1 ! ( x − x 0 ) + f ′ ′ ( x 0 ) 2 ! ( x − x 0 ) 2 + . . . + f ( n ) ( x 0 ) n ! ( x − x 0 ) n T n ( x ) = ∑ i = 0 i = n f ( i ) ( x 0 ) i ! ( x − x 0 ) i T_n(x)=f(x_0)+\frac{f'(x_0)}{1!}(x-x_0)+\frac{f''(x_0)}{2!}(x-x_0)^2+...+\frac{f^{(n)}(x_0)}{n!}(x-x_0)^n\\T_n(x)=\sum_{i=0}^{i=n}\frac{f^{(i)}(x_0)}{i!}(x-x_0)^i T n ( x ) = f ( x 0 ) + 1 ! f ′ ( x 0 ) ( x − x 0 ) + 2 ! f ′ ′ ( x 0 ) ( x − x 0 ) 2 + . . . + n ! f ( n ) ( x 0 ) ( x − x 0 ) n T n ( x ) = ∑ i = 0 i = n i ! f ( i ) ( x 0 ) ( x − x 0 ) i
当x 0 = 0 x_0=0 x 0 = 0 时有麦克劳林公式
泰勒展开
函数f f f 的泰勒多项式即为其泰勒展开
重要函数泰勒展开:
e x = ∑ i = 0 ∞ x i i ! l n ( 1 + x ) = ∑ i = 1 ∞ ( − 1 ) i + 1 x i i 1 1 + x = ∑ i = 0 ∞ ( − 1 ) i x i 1 1 − x = ∑ i = 0 ∞ x i 1 1 − q x = ∑ i = 0 ∞ q i x i ( 1 + x ) a = ∑ i = 0 ∞ ∏ j = 1 n ( a − j + 1 ) i ! x i e^x=\sum_{i=0}^{\infty}\frac{x^i}{i!}\\
ln(1+x)=\sum_{i=1}^{\infty}(-1)^{i+1}\frac{x^i}{i}\\
\frac{1}{1+x}=\sum_{i=0}^{\infty}(-1)^ix^i\\
\frac{1}{1-x}=\sum_{i=0}^{\infty}x^i\\
\frac{1}{1-qx}=\sum_{i=0}^{\infty}q^ix^i\\
(1+x)^a=\sum_{i=0}^{\infty}\frac{\prod_{j=1}^n(a-j+1)}{i!}x^i
e x = i = 0 ∑ ∞ i ! x i l n ( 1 + x ) = i = 1 ∑ ∞ ( − 1 ) i + 1 i x i 1 + x 1 = i = 0 ∑ ∞ ( − 1 ) i x i 1 − x 1 = i = 0 ∑ ∞ x i 1 − q x 1 = i = 0 ∑ ∞ q i x i ( 1 + x ) a = i = 0 ∑ ∞ i ! ∏ j = 1 n ( a − j + 1 ) x i
普通生成函数
对于一个无穷序列a a a ,定义其普通生成函数为∑ i = 0 ∞ a i x i \sum_{i=0}^{\infty}a_ix^i ∑ i = 0 ∞ a i x i
小练习:
序列1 , 0 , 1 , 0... {1,0,1,0...} 1 , 0 , 1 , 0 . . . 的普通生成函数为∑ i = 0 ∞ x 2 i = ∑ i = 0 ∞ ( x 2 ) i = 1 1 − x 2 \sum_{i=0}^{\infty}x^{2i}=\sum_{i=0}^{\infty}(x^2)^{i}=\frac{1}{1-x^2} ∑ i = 0 ∞ x 2 i = ∑ i = 0 ∞ ( x 2 ) i = 1 − x 2 1
序列0 , 1 , 0 , 1... {0,1,0,1...} 0 , 1 , 0 , 1 . . . 的普通生成函数为x ∑ i = 0 ∞ x 2 i = x ∑ i = 0 ∞ ( x 2 ) i = x 1 − x 2 x\sum_{i=0}^{\infty}x^{2i}=x\sum_{i=0}^{\infty}(x^2)^{i}=\frac{x}{1-x^2} x ∑ i = 0 ∞ x 2 i = x ∑ i = 0 ∞ ( x 2 ) i = 1 − x 2 x
序列右移普通生成函数乘以x x x ,记得处理好常数项
序列1 , 2 , 3 , . . . n , . . . 1,2,3,...n,... 1 , 2 , 3 , . . . n , . . . 的普通生成函数为∑ i = 0 ∞ ( i + 1 ) x i = ∑ i = 1 ∞ i x i − 1 = ∑ i = 1 ∞ ( x i ) ′ = ( ∑ i = 0 ∞ x i − 1 ) ′ = ( 1 1 − x − 1 ) ′ = 1 ( 1 − x ) 2 \sum_{i=0}^{\infty}(i+1)x^i=\sum_{i=1}^{\infty}ix^{i-1}=\sum_{i=1}^{\infty}(x^i)'=(\sum_{i=0}^{\infty}x^i-1)'=(\frac 1 {1-x}-1)'=\frac{1}{(1-x)^2} ∑ i = 0 ∞ ( i + 1 ) x i = ∑ i = 1 ∞ i x i − 1 = ∑ i = 1 ∞ ( x i ) ′ = ( ∑ i = 0 ∞ x i − 1 ) ′ = ( 1 − x 1 − 1 ) ′ = ( 1 − x ) 2 1
是不是怪复杂的,其实我们可以使用错位相减的思路
设S S S 为该序列普通生成函数
S = 1 + 2 x + 3 x 2 + 4 x 3 + . . . x S = 0 + x + 2 x 2 + 3 x 3 + . . . ( 1 − x ) S = 1 + x + x 2 + x 3 + . . . = 1 1 − x S = 1 ( 1 − x ) 2 S=1+2x+3x^2+4x^3+...\\xS=0+x+2x^2+3x^3+...\\(1-x)S=1+x+x^2+x^3+...=\frac{1}{1-x}\\S=\frac{1}{(1-x)^2} S = 1 + 2 x + 3 x 2 + 4 x 3 + . . . x S = 0 + x + 2 x 2 + 3 x 3 + . . . ( 1 − x ) S = 1 + x + x 2 + x 3 + . . . = 1 − x 1 S = ( 1 − x ) 2 1
序列1 , 3 , 5 , 7 , . . . , 2 n − 1 , . . . 1,3,5,7,...,2n-1,... 1 , 3 , 5 , 7 , . . . , 2 n − 1 , . . . 的普通生成函数为S S S
S = 1 + 3 x + 5 x 2 + 7 x 3 + . . . x S = 0 + x + 3 x 2 + 5 x 3 + . . . ( 1 − x ) S = 1 + 2 x + 2 x 2 + 2 x 3 + . . . = 1 + 2 x 1 − x = 1 + x ( 1 − x ) 2 S=1+3x+5x^2+7x^3+...\\xS=0+x+3x^2+5x^3+...\\(1-x)S=1+2x+2x^2+2x^3+...=1+\frac{2x}{1-x}=\frac{1+x}{(1-x)^2} S = 1 + 3 x + 5 x 2 + 7 x 3 + . . . x S = 0 + x + 3 x 2 + 5 x 3 + . . . ( 1 − x ) S = 1 + 2 x + 2 x 2 + 2 x 3 + . . . = 1 + 1 − x 2 x = ( 1 − x ) 2 1 + x
Fibonacci \text{Fibonacci} Fibonacci 的普通生成函数:
S = 1 1 − x − x 2 S=\frac1 {1-x-x^2} S = 1 − x − x 2 1
C a t l a n Catlan C a t l a n 的普通生成函数:
G = ∑ i = 0 ∞ c i x i = ∑ i = 0 ∞ c i + 1 x i + 1 + 1 = ∑ i = 0 ∞ ∑ j = 0 i c j c i − j x i + 1 + 1 = x ∑ i = 0 ∞ ∑ j = 0 i c j x j c i − j x i − j + 1 = x ∑ j = 0 ∞ c j x j ∑ i = j ∞ c i − j x i − j + 1 G=\sum_{i=0}^{\infty}c_ix^i=\sum_{i=0}^{\infty}c_{i+1}x^{i+1}+1\\=\sum_{i=0}^{\infty}\sum_{j=0}^{i}c_jc_{i-j} x^{i+1}+1=x\sum_{i=0}^{\infty}\sum_{j=0}^{i}c_jx^jc_{i-j}x^{i-j}+1\\=x\sum_{j=0}^{\infty}c_jx^j\sum_{i=j}^{\infty}c_{i-j}x^{i-j}+1 G = ∑ i = 0 ∞ c i x i = ∑ i = 0 ∞ c i + 1 x i + 1 + 1 = ∑ i = 0 ∞ ∑ j = 0 i c j c i − j x i + 1 + 1 = x ∑ i = 0 ∞ ∑ j = 0 i c j x j c i − j x i − j + 1 = x ∑ j = 0 ∞ c j x j ∑ i = j ∞ c i − j x i − j + 1
令k = i − j k=i-j k = i − j
G = x ∑ j = 0 ∞ c j x j ∑ k = 0 ∞ c k x k + 1 = x G 2 + 1 G=x\sum_{j=0}^{\infty}c_jx^j\sum_{k=0}^{\infty}c_kx^k+1=xG^2+1 G = x ∑ j = 0 ∞ c j x j ∑ k = 0 ∞ c k x k + 1 = x G 2 + 1
G = 1 ± 1 − 4 x 2 x G=\frac{1\pm \sqrt{1-4x}}{2x} G = 2 x 1 ± 1 − 4 x
观察G G G 的常数项,由于x x x 非变量
考虑将1 − x 1-x 1 − x 泰勒展开
1 − x = 1 + x 2 − x 2 8 + . . . 1 − 4 x = 1 − 2 x − 2 x 2 + . . . \sqrt{1-x}=1+\frac x 2-\frac {x^2} 8+...\\\sqrt{1-4x}=1-2x-2x^2+... 1 − x = 1 + 2 x − 8 x 2 + . . . 1 − 4 x = 1 − 2 x − 2 x 2 + . . .
若取加号
G = 2 − 2 x − 2 x 2 2 x = 1 x − 1 − x G=\frac{2-2x-2x^2}{2x}=\frac 1 x-1-x G = 2 x 2 − 2 x − 2 x 2 = x 1 − 1 − x
常数项不对
取减号符合
故G = 1 − 1 − 4 x 2 x G=\frac{1-\sqrt{1-4x}}{2x} G = 2 x 1 − 1 − 4 x
将G G G 泰勒展开整理一波可以得到c n c_n c n 的通项
c n = 1 k + 1 C 2 k k c_n=\frac 1 {k+1}C_{2k}^k c n = k + 1 1 C 2 k k
指数生成函数
对于一个无穷序列a a a ,定义其普通生成函数为∑ i = 0 ∞ a i x i i ! \sum_{i=0}^{\infty}a_i\frac{x^i}{i!} ∑ i = 0 ∞ a i i ! x i
普通生成函数通常用来解决无标号计数问题,指数生成函数通常用来解决带标号的计数问题。
排列数P , p n = n ! \text{P},p_n=n! P , p n = n ! 的指数生成函数:1 1 − x \frac 1 {1-x} 1 − x 1
圆排列数C , c n = ( n − 1 ) ! \text{C},c_n=(n-1)! C , c n = ( n − 1 ) ! 的指数生成函数:l n ( 1 1 − x ) ln(\frac{1}{1-x}) l n ( 1 − x 1 )
注意到P = e C P=e^C P = e C ,这是一个非常有趣的性质
考虑排列数和圆排列数的关系
将排列做一个置换群分解
每一个排列唯一对应一个置换群集合
对于确定的n n n 个位置组成的置换,其方案数有( n − 1 ) ! = c n (n-1)!=c_n ( n − 1 ) ! = c n 即圆排列
故每一个排列能拆成若干个圆排列
可以证明像P \text P P 这样能分解成若干个C \text C C 的指数 生成函数
P = e C P=e^C P = e C
eg:
n n n 个点形成森林的方案数的指数生成函数为F \text F F
n n n 个点形成树的方案数的指数生成函数为T \text T T
则F = e T F=e^T F = e T
错排数的指数生成函数F \text F F 可以分解成若干个无自环的置换D \text D D
D = C − x F = e D D=C-x\\F=e^D D = C − x F = e D
n n n 个点的有标号无向连通图个数的指数生成函数为F \text F F
n n n 个点的有标号无向图个数的指数生成函数为G \text G G
则G = e F G=e^F G = e F
多项式
多项式的表示
小学我们就学过多项式的概念
例如F ( x ) = x 2 + 2 x + 1 F(x)=x^2+2x+1 F ( x ) = x 2 + 2 x + 1 这就是一个二次多项式
多项式的系数表示法
这是一般的多项式常用的表示方法
对于一个n n n 次多项式,我们可以用n + 1 n+1 n + 1 个系数表示出这个多项式
例如上面的F ( x ) F(x) F ( x ) ,我们可以用1 , 2 , 1 1,2,1 1 , 2 , 1 表示这个多项式
多项式的点值表示法
我们可以把一个多项式理解成一个高次函数
对于每一个x x x 我们都能得到这个函数的一个y y y 值(点值)
对于一个n n n 次多项式,我们可以用n + 1 n+1 n + 1 个点值表示出这个多项式
例如上面的F ( x ) F(x) F ( x ) ,我们可以用1 , 4 , 9 1,4,9 1 , 4 , 9 来表示出这个多项式
多项式加法
即F ( x ) + G ( x ) F(x)+G(x) F ( x ) + G ( x ) ,F ( x ) F(x) F ( x ) 为n n n 次多项式,G ( x ) G(x) G ( x ) 为m m m 次多项式,不妨设n < m n<m n < m
对于系数表示法,把两个多项式的系数相加即可
对于点值表示法,取m m m 个不同的x x x 值代入两个多项式得到的点值相加即可
多项式乘法
即F ( x ) × G ( x ) F(x)\times G(x) F ( x ) × G ( x ) ,F ( x ) F(x) F ( x ) 为n n n 次多项式,G ( x ) G(x) G ( x ) 为m m m 次多项式,不妨设n < m n<m n < m
我们可以将多项式乘法理解为数字竖式乘法的形式
对于系数表示法,O ( n m ) O(nm) O ( n m ) 枚举即可
对于点值表示法,取n + m n+m n + m 个不同的x x x 值代入两个多项式中得到的点值相乘即可
多项式乘法
FFT
快速傅里叶变换Fast Fast TLE
复数
了解这部分可以跳过
初一时我们学过实数的概念
我们也学过一元二次方程
当碰到x 2 + 2 x + 2 = 0 x^2+2x+2=0 x 2 + 2 x + 2 = 0 这样Δ < 0 \Delta<0 Δ < 0 的方程时
老师告诉我们这是无实数解的,因为负数在实数范围内没有平方根
但在复数范围内一切皆有可能
复数域也是目前最大的定义域
定义与复平面
我们把形如z = a + b i z=a+bi z = a + b i (a , b a,b a , b 均为实数)的数称为复数,其中a a a 称为实部,b b b 称为虚部,i i i 称为虚数 单位。当z z z 的虚部等于零时,常称z z z 为实数;当z z z 的虚部 不等于零时,实部等于零时,常称z z z 为纯虚数 。
——摘自百度百科
我们可以把复数域映射到平面直角坐标系上,一般称该平面为复平面
用一个点( a , b ) (a,b) ( a , b ) 表示一个复数,对应a + b i a+bi a + b i
复数的三角形式
一个复数可以表示成z = r ( c o s θ + i s i n θ ) z=r(cos\theta+isin\theta) z = r ( c o s θ + i s i n θ ) 的形式,r r r 是z z z 的模,θ \theta θ 是z z z 的辐角
复数的运算
z 1 = a 1 + b 1 i = r 1 ( c o s θ 1 + i s i n θ 1 ) , z 2 = a 2 + b 2 i = r 2 ( c o s θ 2 + i s i n θ 2 ) z_1=a_1+b_1i=r_1(cos\theta_1+isin\theta_1),z_2=a_2+b_2i=r_2(cos\theta_2+isin\theta_2) z 1 = a 1 + b 1 i = r 1 ( c o s θ 1 + i s i n θ 1 ) , z 2 = a 2 + b 2 i = r 2 ( c o s θ 2 + i s i n θ 2 )
z 1 + z 2 = ( a 1 + a 2 ) + ( b 1 + b 2 ) i z 1 ∗ z 2 = ( a 1 ∗ a 2 − b 1 ∗ b 2 ) + ( a 1 ∗ b 2 + a 2 ∗ b 1 ) i z 1 ∗ z 2 = r 1 ∗ r 2 ( c o s ( θ 1 + θ 2 ) + i s i n ( θ 1 + θ 2 ) ) z 1 z 2 = r 1 r 2 ( c o s ( θ 1 − θ 2 ) + i s i n ( θ 1 − θ 2 ) ) z_1+z_2=(a_1+a_2)+(b_1+b_2)i\\z_1*z_2=(a_1*a_2-b_1*b_2)+(a_1*b_2+a_2*b_1)i\\z_1*z_2=r_1*r_2(cos(\theta_1+\theta_2)+isin(\theta_1+\theta_2))\\\frac{z_1}{z_2}=\frac{r_1}{r_2}(cos(\theta_1-\theta_2)+isin(\theta_1-\theta_2)) z 1 + z 2 = ( a 1 + a 2 ) + ( b 1 + b 2 ) i z 1 ∗ z 2 = ( a 1 ∗ a 2 − b 1 ∗ b 2 ) + ( a 1 ∗ b 2 + a 2 ∗ b 1 ) i z 1 ∗ z 2 = r 1 ∗ r 2 ( c o s ( θ 1 + θ 2 ) + i s i n ( θ 1 + θ 2 ) ) z 2 z 1 = r 2 r 1 ( c o s ( θ 1 − θ 2 ) + i s i n ( θ 1 − θ 2 ) )
具体推算过程可以去系统的学习一下复数,毕竟我们在搞OI
单位根
我们称方程x n = 1 x^n=1 x n = 1 的所有复数解ω n k , k ∈ [ 0 , n − 1 ] \omega_n^k,k\in[0,n-1] ω n k , k ∈ [ 0 , n − 1 ] 为n n n 次单位根
ω n k = c o s 2 k π n + i s i n 2 k π n \omega_n^k=cos\frac{2k\pi}{n}+isin\frac{2k\pi}{n} ω n k = c o s n 2 k π + i s i n n 2 k π
显然ω n 0 = 1 \omega_n^0=1 ω n 0 = 1
性质
1.( ω n 1 ) k = ω n k (\omega_n^1)^k=\omega_n^k ( ω n 1 ) k = ω n k
由定义易知
2.ω n k = ω 2 n 2 k \omega_n^k=\omega_{2n}^{2k} ω n k = ω 2 n 2 k
ω 2 n 2 k = c o s 4 k π 2 n + i s i n 4 k π 2 n = c o s 2 k π n + i s i n 2 k π n = ω n k \omega_{2n}^{2k}=cos\frac{4k\pi}{2n}+isin\frac{4k\pi}{2n}=cos\frac{2k\pi}{n}+isin\frac{2k\pi}{n}=\omega_n^k ω 2 n 2 k = c o s 2 n 4 k π + i s i n 2 n 4 k π = c o s n 2 k π + i s i n n 2 k π = ω n k
3.ω n k = − ω n k + n 2 , k < n 2 \omega_n^k=-\omega_n^{k+\frac n 2},k<\frac n 2 ω n k = − ω n k + 2 n , k < 2 n
ω n k + n 2 = ω n k ∗ ω n n 2 = ω n k ∗ ( c o s π + i s i n π ) = − ω n k \omega_n^{k+\frac n 2}=\omega_n^k*\omega_n^{\frac n 2}=\omega_n^k*(cos\pi+isin\pi)=-\omega_n^k ω n k + 2 n = ω n k ∗ ω n 2 n = ω n k ∗ ( c o s π + i s i n π ) = − ω n k
FFT推导
问题叙述:
给定一个 n n n 次多项式 F ( x ) F(x) F ( x ) ,和一个 m m m 次多项式 G ( x ) G(x) G ( x ) ,求出 F ( x ) F(x) F ( x ) 和 G ( x ) G(x) G ( x ) 的卷积(F ( x ) × G ( x ) F(x)\times G(x) F ( x ) × G ( x ) 的每项系数)
F ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n x n G ( x ) = b 0 + b 1 x + b 2 x 2 + . . . + b n x m F(x)=a_0+a_1x+a_2x^2+...+a_nx^n\\G(x)=b_0+b_1x+b_2x^2+...+b_nx^m F ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n x n G ( x ) = b 0 + b 1 x + b 2 x 2 + . . . + b n x m
先将F ( x ) F(x) F ( x ) 由系数表示法变成点值表示法,由于暴力是O ( n × ( n + m ) ) O(n\times(n+m)) O ( n × ( n + m ) ) 的,我们需要更优秀的做法
默认n n n 为2 2 2 的次幂
将F ( x ) F(x) F ( x ) 按x x x 幂次的奇偶性分离
记F 0 ( x ) = a 0 + a 2 x + a 4 x 2 + a n x n 2 F 1 ( x ) = a 1 + a 3 x + a 5 x 2 + a n − 1 x n 2 − 1 F_0(x)=a_0+a_2x+a_4x^2+a_nx^{\frac n 2}\\F_1(x)=a_1+a_3x+a_5x^2+a_{n-1}x^{\frac n 2-1} F 0 ( x ) = a 0 + a 2 x + a 4 x 2 + a n x 2 n F 1 ( x ) = a 1 + a 3 x + a 5 x 2 + a n − 1 x 2 n − 1
则F ( x ) = F 0 ( x 2 ) + x F 1 ( x 2 ) F(x)=F_0(x^2)+xF_1(x^2) F ( x ) = F 0 ( x 2 ) + x F 1 ( x 2 )
代入x = ω n k , x = ω n k + n 2 , k < n 2 x=\omega_n^k,x=\omega_n^{k+\frac n 2},k<\frac n 2 x = ω n k , x = ω n k + 2 n , k < 2 n
F ( ω n k ) = F 0 ( ω n 2 k ) + ω n k F 1 ( ω n 2 k ) F(\omega_n^k)=F_0(\omega_n^{2k})+\omega_n^kF_1(\omega_n^{2k}) F ( ω n k ) = F 0 ( ω n 2 k ) + ω n k F 1 ( ω n 2 k )
F ( ω n k + n 2 ) = F 0 ( ω n 2 k + n ) + ω n k + n 2 F 1 ( ω n 2 k + n ) F(\omega_n^{k+\frac n 2})=F_0(\omega_n^{2k+n})+\omega_n^{k+\frac n 2}F_1(\omega_n^{2k+n}) F ( ω n k + 2 n ) = F 0 ( ω n 2 k + n ) + ω n k + 2 n F 1 ( ω n 2 k + n )
由ω n n = 1 \omega_n^n=1 ω n n = 1
F ( ω n k + n 2 ) = F 0 ( ω n 2 k ) + ω n k + n 2 F 1 ( ω n 2 k ) F(\omega_n^{k+\frac n 2})=F_0(\omega_n^{2k})+\omega_n^{k+\frac n 2}F_1(\omega_n^{2k}) F ( ω n k + 2 n ) = F 0 ( ω n 2 k ) + ω n k + 2 n F 1 ( ω n 2 k )
由ω n k = − ω n k + n 2 \omega_n^k=-\omega_n^{k+\frac n 2} ω n k = − ω n k + 2 n
F ( ω n k + n 2 ) = F 0 ( ω n 2 k ) − ω n k F 1 ( ω n 2 k ) F(\omega_n^{k+\frac n 2})=F_0(\omega_n^{2k})-\omega_n^kF_1(\omega_n^{2k}) F ( ω n k + 2 n ) = F 0 ( ω n 2 k ) − ω n k F 1 ( ω n 2 k )
我们惊喜的发现F ( ω n k ) F(\omega_n^k) F ( ω n k ) 和F ( ω n k + n 2 ) F(\omega_n^{k+\frac n 2}) F ( ω n k + 2 n ) 的求式不同点只有F 1 ( x ) F_1(x) F 1 ( x ) 这一项的系数互为相反数
而对于F 0 ( x ) , F 1 ( x ) F_0(x),F_1(x) F 0 ( x ) , F 1 ( x ) 这两个多项式都可以重复上述过程继续奇偶分离做
这也是我们需要n n n 为2的次幂的原因
void FFT(C *a,int lim,int opt){
if(lim==1)return ;
C a1[(lim>>1)+5],a2[(lim>>1)+5];
for(int i=0;i<=lim;i+=2){
a1[i>>1]=a[i];//F_0
a2[i>>1]=a[i+1];//F_1
}
FFT(lim>>1,a1,opt);
FFT(lim>>1,a2,opt);
C w=(C){cos(2.0*pai/lim),opt*sin(2.0*pai/lim)};//lim次单位根
C p=(C){1,0};
for(int i=0;i<(lim>>1);i++,p=p*w){
C t=p*a2[i];
a[i]=a1[i]+t;
a[i+(lim>>1)]=a1[i]-t;
}
return ;
}
我们能发现FFT \text{FFT} FFT 合并的顺序为原顺序的二进制反转,得出非递归版,这个部分不过多叙述
void FFT(C *a,int lim,int opt){
for(int i=0;i<lim;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int mid=1;mid<lim;mid<<=1){//枚举中点
C w=(C){cos(pai/mid),opt*sin(pai/mid)};
int len=mid<<1;//长度
for(int j=0;j<lim;j+=len){//每段起始位置
C p=(C){1,0};
for(int k=0;k<mid;k++,p=p*w){//每段前半段
C u=a[j+k],v=p*a[j+mid+k];
a[j+k]=u+v;
a[j+mid+k]=u-v;
}
}
}
return ;
}
NTT
快速数论变换
由于复数运算常数巨大,且有精度问题,在模意义下,NTT \text{NTT} NTT 利用原根完成和FTT \text{FTT} FTT 完全相同的操作
void NTT(long long *f,int lim,int opt){
for(int i=0;i<lim;i++)if(i<r[i])swap(f[i],f[r[i]]);
for(int mid=1;mid<lim;mid<<=1){
long long wn=power(opt==1?G:Gi,(mod-1)/(mid<<1));
int len=mid<<1;
for(int j=0;j<lim;j+=len){
long long w=1;
for(int k=0;k<mid;k++,w=w*wn%mod){
long long u=f[j+k],v=w*f[j+k+mid]%mod;
f[j+k]=(u+v)%mod;
f[j+k+mid]=(u-v+mod)%mod;
}
}
}
if(opt==1)return ;
long long inv=power(lim,mod-2);
for(int i=0;i<lim;i++)f[i]=f[i]*inv%mod;
return ;
}
这里放一份速度还行的预处理原根板子
int pw[2][4*maxn];
void pre(int lim){
int c=0;
for(int i=1;i<lim;i<<=1,c++){
pw[0][i]=pw[1][i]=1;
pw[0][i+1]=power(G,(mod-1)/(i<<1));
pw[1][i+1]=power(Gi,(mod-1)/(i<<1));
for(int j=2;j<i;j++){
pw[0][i+j]=1ll*pw[0][i+j-1]*pw[0][i+1]%mod;
pw[1][i+j]=1ll*pw[1][i+j-1]*pw[1][i+1]%mod;
}
}
return ;
}
void NTT(int *f,int lim,int opt){
for(int i=1;i<lim;i++)if(i<rev[i])swap(f[i],f[rev[i]]);
int op=(opt==-1),c=0;
for(int mid=1;mid<lim;mid<<=1,c++){
for(int j=0;j<lim;j+=(mid<<1)){
for(int k=0;k<mid;k++){
int u=f[j+k],v=1ll*f[j+k+mid]*pw[op][mid+k]%mod;
f[j+k]=add(u+v);
f[j+k+mid]=sub(u-v);
}
}
}
if(opt==1)return;
int inv=power(lim,mod-2);
for(int i=0;i<lim;i++)f[i]=1ll*f[i]*inv%mod;
return ;
}
任意模数多项式乘法
一种是三模NTT(做9次ntt),另一种是MTT(7次FFT或4次FFT)
MTT(拆系数FFT)
指毛爷爷在2016年国家集训队论文中给出的优秀任意模数多项式乘法优化
我们把两 n ∈ [ 1 , 1 0 5 ] n\in[1,10^5] n ∈ [ 1 , 1 0 5 ] 次多项式系数值域定为 [ 1 , 1 0 9 ] [1,10^9] [ 1 , 1 0 9 ] ,模数为 [ 1 , 1 0 9 ] [1,10^9] [ 1 , 1 0 9 ] 的一个质数 p p p
那么答案是 1 0 23 10^{23} 1 0 2 3 级别,double精度不够
考虑一个 b ∼ w , w 为 值 域 b\sim \sqrt w,w为值域 b ∼ w , w 为 值 域 把系数分成两部分计算
F ( x ) = b A ( x ) + B ( x ) G ( x ) = b C ( x ) + D ( x ) F(x)=bA(x)+B(x)\\G(x)=bC(x)+D(x) F ( x ) = b A ( x ) + B ( x ) G ( x ) = b C ( x ) + D ( x )
则
F ( x ) G ( x ) = b 2 A ( x ) C ( x ) + b ( A ( x ) D ( x ) + B ( x ) C ( x ) ) + B ( x ) D ( x ) F(x)G(x)=b^2A(x)C(x)+b(A(x)D(x)+B(x)C(x))+B(x)D(x) F ( x ) G ( x ) = b 2 A ( x ) C ( x ) + b ( A ( x ) D ( x ) + B ( x ) C ( x ) ) + B ( x ) D ( x )
三个部分的多项式乘法值域为 [ 1 , 1 0 15 ] [1,10^{15}] [ 1 , 1 0 1 5 ] ,double的精度足够处理
至此,我们得到了一个7次FFT的做法(对 A , B , C , D A,B,C,D A , B , C , D 分别dft一次,对 A C , A D + B C , B D AC,AD+BC,BD A C , A D + B C , B D 分别idft3次)
接下来考虑将两个多项式的点值表示由一遍dft得到
记 P ( x ) = A ( x ) + i B ( x ) Q ( x ) = A ( x ) − i B ( x ) P(x)=A(x)+iB(x)\\Q(x)=A(x)-iB(x) P ( x ) = A ( x ) + i B ( x ) Q ( x ) = A ( x ) − i B ( x )
若得到了 P , Q P,Q P , Q 两辅助多项式,我们通过加减即能得到 A , B A,B A , B
考虑 P , Q P,Q P , Q 的关系
P ( ω k ) = A ( ω k ) + i B ( ω k ) = ∑ j = 0 n a j ω j k + i b j ω j k = ∑ j = 0 n ( a j + i b j ) ( cos 2 π j k n + i sin 2 π j k n ) P(\omega^k)=A(\omega^k)+iB(\omega^k)=\sum_{j=0}^na_j\omega^{jk}+ib_j\omega^{jk}\\=\sum_{j=0}^n(a_j+ib_j)(\cos\frac{2\pi jk}{n}+i\sin \frac{2\pi jk}{n}) P ( ω k ) = A ( ω k ) + i B ( ω k ) = ∑ j = 0 n a j ω j k + i b j ω j k = ∑ j = 0 n ( a j + i b j ) ( cos n 2 π j k + i sin n 2 π j k )
设 X = cos 2 π j k n + i sin 2 π j k n X=\cos\frac{2\pi jk}{n}+i\sin \frac{2\pi jk}{n} X = cos n 2 π j k + i sin n 2 π j k
P ( ω k ) = ∑ j = 0 n ( a j + i b j ) ( cos X + i sin X ) = ∑ j = 0 n a j cos X + i a j sin X + i b j cos X − b j sin X = ∑ j = 0 n a j cos X − b j sin X + i ( a j sin X + b j cos X ) P(\omega^k)=\sum_{j=0}^n(a_j+ib_j)(\cos X+i\sin X)=\sum_{j=0}^na_j\cos X+ia_j\sin X+ib_j\cos X-b_j\sin X\\=\sum_{j=0}^na_j\cos X-b_j\sin X+i(a_j\sin X+b_j\cos X) P ( ω k ) = ∑ j = 0 n ( a j + i b j ) ( cos X + i sin X ) = ∑ j = 0 n a j cos X + i a j sin X + i b j cos X − b j sin X = ∑ j = 0 n a j cos X − b j sin X + i ( a j sin X + b j cos X )
Q ( ω k ) = ∑ j = 0 n ( a j − i b j ) ( cos X + i sin X ) = ∑ j = 0 n a j cos X + i a j sin X − i b j cos X + b j sin X = ∑ j = 0 n a j cos X + b j sin X + i ( a j sin X − b j cos X ) Q(\omega^k)=\sum_{j=0}^n(a_j-ib_j)(\cos X+i\sin X)=\sum_{j=0}^na_j\cos X+ia_j\sin X-ib_j\cos X+b_j\sin X\\=\sum_{j=0}^na_j\cos X+b_j\sin X+i(a_j\sin X-b_j\cos X) Q ( ω k ) = ∑ j = 0 n ( a j − i b j ) ( cos X + i sin X ) = ∑ j = 0 n a j cos X + i a j sin X − i b j cos X + b j sin X = ∑ j = 0 n a j cos X + b j sin X + i ( a j sin X − b j cos X )
记 conj ( x ) \text{conj}(x) conj ( x ) 表示 x x x 的共轭复数
Q ( ω n − k ) = ∑ j = 0 n a j cos X − b j sin X − i ( a j sin X + b j cos X ) = conj ( P ( ω k ) ) Q(\omega^{n-k})=\sum_{j=0}^na_j\cos X-b_j\sin X-i(a_j\sin X+b_j\cos X)=\text{conj}(P(\omega^k)) Q ( ω n − k ) = ∑ j = 0 n a j cos X − b j sin X − i ( a j sin X + b j cos X ) = conj ( P ( ω k ) )
那么我们对 P P P dft一次就能得到 P , Q P,Q P , Q 的点值表达了!
我们成功的得到了一个一次dft,一次idft求卷积的神必做法
同时,我们也得到了两次dft,两次idft求任意模数多项式乘法的神必做法!
多项式求导与不定积分
void dervt(int lim,long long *f){
for(int i=0;i<lim-1;i++)f[i]=f[i+1]*(i+1)%mod;
f[lim-1]=0;
return ;
}
void integ(int lim,long long *f){
for(int i=lim-1;i>=1;i--)f[i]=f[i-1]*power(i,mod-2)%mod;
f[0]=0;
return ;
}
多项式求逆
【模板】多项式乘法逆
即给定n − 1 n-1 n − 1 次多项式F(x) \text{F(x)} F(x) ,求多项式G(x) \text{G(x)} G(x) 满足,F(x) ∗ G(x) ≡ 1 m o d x n \text{F(x)}*\text{G(x)}\equiv1\mod x^n F(x) ∗ G(x) ≡ 1 m o d x n
考虑递归求解
已知
H F ∗ H ≡ 1 m o d x n 2 F ∗ G ≡ 1 m o d x n \text H\\\text{F}*\text{H}\equiv1\mod x^{\frac n 2}\\\text{F}*\text{G}\equiv1\mod x^n H F ∗ H ≡ 1 m o d x 2 n F ∗ G ≡ 1 m o d x n
G − H ≡ 0 m o d x n 2 ( G − H ) 2 ≡ 0 m o d x n G 2 − 2 GH + H 2 ≡ 0 m o d x n G − 2 H + FH 2 ≡ 0 m o d x n G ≡ 2 H − FH 2 m o d x n \text{G}-\text{H}\equiv0\mod x^{\frac n 2}\\(\text{G}-\text{H})^2\equiv0\mod x^n\\\text{G}^2-2\text{GH}+\text{H}^2\equiv 0 \mod x^n\\\text{G}-2\text{H}+\text{FH}^2\equiv0\mod x^n\\\text G\equiv2\text H-\text {FH}^2\mod x^n G − H ≡ 0 m o d x 2 n ( G − H ) 2 ≡ 0 m o d x n G 2 − 2 GH + H 2 ≡ 0 m o d x n G − 2 H + FH 2 ≡ 0 m o d x n G ≡ 2 H − FH 2 m o d x n
时间复杂度T ( n ) = T ( n 2 ) + O ( n l o g n ) = O ( n l o g n ) T(n)=T(\frac n 2)+O(nlogn)=O(nlogn) T ( n ) = T ( 2 n ) + O ( n l o g n ) = O ( n l o g n )
long long A[maxn<<2];
void inv(int n,long long *f,long long *g){
if(n==1){g[0]=power(f[0],mod-2);return ;}
inv((n+1)>>1,f,g);
int lim=1,k=0;
while(lim<(n<<1))lim<<=1,k++;
for(int i=1;i<lim;i++)r[i]=r[i>>1]>>1|((i&1)<<k-1);
for(int i=0;i<n;i++)A[i]=f[i];
for(int i=n;i<lim;i++)g[i]=A[i]=0;
NTT(g,lim,1);NTT(A,lim,1);
for(int i=0;i<lim;i++)g[i]=(2ll*g[i]%mod-A[i]*g[i]%mod*g[i]%mod+mod)%mod;
NTT(g,lim,-1);
for(int i=n;i<lim;i++)g[i]=0;
return ;
}
多项式开根
【模板】多项式开根
即给定n − 1 n-1 n − 1 次多项式F(x) \text{F(x)} F(x) ,求多项式G(x) \text{G(x)} G(x) 满足,G(x) 2 ≡ F(x) m o d x n \text{G(x)}^2\equiv \text{F(x)}\mod x^n G(x) 2 ≡ F(x) m o d x n
同样递归求解
已知
H H 2 ≡ F m o d x n 2 G 2 ≡ F m o d x n \text H\\\text H^2\equiv \text F\mod x^{\frac n 2}\\\text G^2\equiv \text F\mod x^n H H 2 ≡ F m o d x 2 n G 2 ≡ F m o d x n
G ≡ H m o d x n 2 G − H ≡ 0 m o d x n 2 G 2 − 2 GH + H 2 ≡ 0 m o d x n G ≡ F + H 2 2 H \text G\equiv \text H\mod x^{\frac n 2}\\\text G-\text H\equiv0\mod x^{\frac n 2}\\\text G^2-2\text{GH}+\text H^2\equiv 0 \mod x^n\\\text G\equiv\frac{\text F+\text H^2}{2\text H} G ≡ H m o d x 2 n G − H ≡ 0 m o d x 2 n G 2 − 2 GH + H 2 ≡ 0 m o d x n G ≡ 2 H F + H 2
求逆即可
long long B[maxn<<2],C[maxn<<2];
long long inv2=power(2,mod-2);
void sqrt(int n,long long *f,long long *g){
if(n==1){g[0]=1;return ;}
sqrt((n+1)>>1,f,g);
inv(n,g,B);
int lim=1,k=0;
while(lim<(n<<1))lim<<=1,k++;
for(int i=1;i<lim;i++)r[i]=r[i>>1]>>1|((i&1)<<k-1);
for(int i=0;i<n;i++)C[i]=f[i];
for(int i=n;i<lim;i++)B[i]=C[i]=0;
NTT(g,lim,1);NTT(B,lim,1);NTT(C,lim,1);
for(int i=0;i<lim;i++)g[i]=(C[i]+g[i]*g[i]%mod)%mod*inv2%mod*B[i]%mod;
NTT(g,lim,-1);
for(int i=n;i<lim;i++)g[i]=0;
return ;
}
多项式ln \text{ln} ln
【模板】多项式对数函数(多项式 ln)
即给定n − 1 n-1 n − 1 次多项式F(x) \text{F(x)} F(x) ,求多项式G(x) \text{G(x)} G(x) 满足,G(x) ≡ ln F(x) m o d x n \text{G(x)}\equiv \text{ln F(x)}\mod x^n G(x) ≡ ln F(x) m o d x n
与前两种思路不太一样,对两边求导
G ′ ≡ F ′ F m o d x n \text G'\equiv\frac {\text F'}{\text F}\mod x^n G ′ ≡ F F ′ m o d x n
求逆+求导+不定积分即可
long long D[maxn<<2];
void ln(int n,long long *f,long long *g){
for(int i=0;i<n;i++)D[i]=f[i];
inv(n,D,g);
dervt(n,D);
int lim=1,k=0;
while(lim<(n<<1))lim<<=1,k++;
for(int i=1;i<lim;i++)r[i]=((r[i>>1]>>1)|((i&1)<<(k-1)));
NTT(D,lim,1);NTT(g,lim,1);
for(int i=0;i<lim;i++)g[i]=D[i]*g[i]%mod;
NTT(g,lim,-1);
integ(n,g);
for(int i=n;i<lim;i++)g[i]=0;
for(int i=0;i<lim;i++)D[i]=0;
return ;
}
牛顿迭代
即给定n − 1 n-1 n − 1 次多项式F(x) \text{F(x)} F(x) ,求多项式G(x) \text{G(x)} G(x) 满足,F(G(x)) ≡ 0 m o d x n \text{F(G(x))}\equiv 0\mod x^n F(G(x)) ≡ 0 m o d x n
同样递归求解
已知
H(x) F(H(x)) ≡ 0 m o d x n 2 \text{H(x)}\\\text{F(H(x))}\equiv 0\mod x^{\frac n 2} H(x) F(H(x)) ≡ 0 m o d x 2 n
将F(G(x)) \text{F(G(x))} F(G(x)) 在H(x) \text{H(x)} H(x) 处泰勒展开
F ( G ( x ) ) = ∑ i = 0 i = n F ( i ) ( H ( x ) ) i ! ( G ( x ) − H ( x ) ) i ≡ 0 m o d x n F(G(x))=\sum_{i=0}^{i=n}\frac{F^{(i)}(H(x))}{i!}(G(x)-H(x))^i\equiv 0 \mod x^n F ( G ( x ) ) = ∑ i = 0 i = n i ! F ( i ) ( H ( x ) ) ( G ( x ) − H ( x ) ) i ≡ 0 m o d x n
由于 G ( x ) − H ( x ) G(x)-H(x) G ( x ) − H ( x ) 的最低非0系数项为 x n 2 x^{\frac n 2} x 2 n
则对于任意 i ≥ 2 , ( G ( x ) − H ( x ) ) i ≡ 0 m o d x n i\geq 2,(G(x)-H(x))^i\equiv 0\mod x^n i ≥ 2 , ( G ( x ) − H ( x ) ) i ≡ 0 m o d x n
故 F ( G ( x ) ) ≡ H ( x ) − F ( H ( x ) ) F ′ ( H ( x ) ) m o d x n F(G(x))\equiv H(x)-\frac{F(H(x))}{F'(H(x))} \mod x^n F ( G ( x ) ) ≡ H ( x ) − F ′ ( H ( x ) ) F ( H ( x ) ) m o d x n
多项式exp \text{exp} exp
【模板】多项式指数函数(多项式 exp)
即给定n − 1 n-1 n − 1 次多项式F(x) \text{F(x)} F(x) ,求多项式G(x) \text{G(x)} G(x) 满足,G(x) ≡ e F(x) m o d x n \text{G(x)}\equiv e^\text{F(x)}\mod x^n G(x) ≡ e F(x) m o d x n
两边同时取ln \text{ln} ln
ln G ≡ F m o d x n \text{ln G}\equiv \text F \mod x^n ln G ≡ F m o d x n
定义H(x) = ln x-F \text{H(x)}=\text{ln x-F} H(x) = ln x-F ,则
H(G) ≡ 0 m o d x n \text{H(G)}\equiv 0\mod x^n H(G) ≡ 0 m o d x n
牛顿迭代
long long E[maxn<<2],F[maxn<<2];
void exp(int n,long long *f,long long *g){
if(n==1){g[0]=1;return ;}
exp((n+1)>>1,f,g);
ln(n,g,E);
int lim=1,k=0;
while(lim<=(n<<1))lim<<=1,k++;
for(int i=1;i<lim;i++)r[i]=((r[i>>1]>>1)|((i&1)<<(k-1)));
for(int i=0;i<n;i++)F[i]=f[i];
for(int i=n;i<lim;i++)E[i]=F[i]=0;
for(int i=0;i<lim;i++)F[i]=((F[i]-E[i])%mod+mod)%mod;
F[0]++;
NTT(g,lim,1);NTT(F,lim,1);
for(int i=0;i<lim;i++)g[i]=g[i]*F[i]%mod;
NTT(g,lim,-1);
for(int i=n;i<lim;i++)g[i]=0;
for(int i=0;i<n;i++)E[i]=0;
return ;
}
多项式快速幂
【模板】多项式快速幂
long long H[maxn<<2];
void power(int n,int k,long long *f,long long *g){
ln(n,f,g);
for(int i=0;i<n;i++)g[i]=g[i]*k%mod;
exp(n,g,H);
for(int i=0;i<n;i++)g[i]=H[i];
return ;
}
多项式除法
多项式多点求值
多项式多点插值
多项式复合逆