Martian148's blog Martian148's blog
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档

Martian148

一只热爱文科的理科生
首页
  • ICPC 算法笔记
  • ICPC 算法题解
  • 体系结构
  • 高等数学
  • 线性代数
  • 概率论与数理统计
  • 具体数学
  • Martian148的奇思妙想
  • 游记
  • 通识课笔记
关于
  • useful 网站
  • 友情链接
  • 分类
  • 归档
  • 线上赛板子(实时更新)
  • 数据结构

  • 数学

    • 数论
    • 多项式与生成函数
      • 生成函数
        • 幂级数
        • 形式幂级数
        • 形式幂级数的逆元
        • 形式幂级数的求导
        • 形式幂级数的积分
        • 形式幂级数的复合
        • 形式幂级数的其他运算
        • 常生成函数
        • 递推关系
        • 指数生成函数
      • FFT
        • 多项式的表示形式
        • 复数与单位根
        • 快速傅里叶变换
        • 蝴蝶变换
      • NTT
        • 原根
        • NTT 实现
      • 牛顿迭代
      • 多项式求逆
      • 多项式开方
      • 多项式 exp
      • 拉格朗日差值
    • 线性代数
    • 组合数学
    • 博弈论
  • 计算几何

  • 动态规划

  • 图论

  • 字符串

  • 杂项

  • 算法笔记
  • 数学
martian148
2024-08-31
目录

多项式与生成函数

# 多项式与生成函数

# 生成函数

母函数(又翻为生成函数),是求解递推关系巧妙的数学方法,他通过代数手段解决组合计数问题

先思考一个简单的问题:从数字 1,2,3,41,2,3,41,2,3,4 中取出一个或多个相加(每个数字最多只能用一次)能组合成几个数?每个数有几种组合?

image.png

我们构造一个多项式,把他展开

(1+x)(1+x2)(1+x3)(1+x4)=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10 (1+x)(1+x^2)(1+x^3)(1+x^4)=1+x+x^2+2x^3+2x^4+2x^5+2x^6+2x^7+x^8+x^9+x^{10} (1+x)(1+x2)(1+x3)(1+x4)=1+x+x2+2x3+2x4+2x5+2x6+2x7+x8+x9+x10

惊人的发现,每个数的组合数量和系数一样

母函数的作用就是这样:把组合问题的加法与幂级数的乘幂对应起来

普通母函数的定义:对于序列 h0,h1,h2,⋯,h_0,h_1,h_2,\cdots,h0​,h1​,h2​,⋯, 构造函数 g(x)=h0+h1x+h2x2⋯g(x)=h_0+h_1x+h_2x^2\cdotsg(x)=h0​+h1​x+h2​x2⋯,称 g(x)g(x)g(x) 为序列 h0,h1,h2,⋯h_0,h_1,h_2,\cdotsh0​,h1​,h2​,⋯ 的母函数

母函数的实质是无限可微分函数的泰勒计数,有:

11−x=1+x+x2+⋯ \frac{1}{1-x}=1+x+x^2+\cdots 1−x1​=1+x+x2+⋯
11−x2=1+x2+x4+⋯ \frac{1}{1-x^2}=1+x^2+x^4+\cdots 1−x21​=1+x2+x4+⋯

利用母函数的泰勒计数表达,有时可以简单的演算组合计数问题

在袋子中装 nnn 个水果,要求苹果是偶数个,香蕉数是 555 的倍数,句子最多 444 个,梨有 000 个或 111 个,给出 nnn,共有多少种情况?

写出生成函数:

g(x)=(1+x2+x4+⋯)(1+x5+x10+⋯)(1+x+x2+x3+x4)(1+x)=11−x211−x51−x51−x(1+x)=1(1−x)2=∑k=0∞(n+1)xn \begin{aligned} g(x)&=(1+x^2+x^4+\cdots)(1+x^5+x^{10}+\cdots)(1+x+x^2+x^3+x^4)(1+x)\\&=\frac{1}{1-x^2}\frac{1}{1-x^5}\frac{1-x^5}{1-x}(1+x)\\&=\frac{1}{(1-x)^2}\\&=\sum\limits^{\infty}_{k=0}(n+1)x^n\end{aligned} g(x)​=(1+x2+x4+⋯)(1+x5+x10+⋯)(1+x+x2+x3+x4)(1+x)=1−x21​1−x51​1−x1−x5​(1+x)=(1−x)21​=k=0∑∞​(n+1)xn​

最后一步根据牛顿二项式定理得到

# 幂级数

  • 多项式:A(x)=∑i=0naixiA(x)=\sum_{i=0}^n a_i x^iA(x)=∑i=0n​ai​xi
  • 形式幂级数:A(x)=∑i≥0aixiA(x)=\sum_{i\ge 0} a_i x^iA(x)=∑i≥0​ai​xi

形式幂级数之间可以有一些运算:

设 A(x)=∑i≥0aixi,B(x)=∑i≥0bixiA(x)=\sum_{i\ge 0}a_ix^i, B(x)=\sum_{i\ge 0} b_i x^iA(x)=∑i≥0​ai​xi,B(x)=∑i≥0​bi​xi

  • 加法:A(x)+B(x)=∑i≥0(ai+bi)xiA(x)+B(x)=\sum_{i\ge 0}(a_i+b_i)x^iA(x)+B(x)=∑i≥0​(ai​+bi​)xi
  • 乘法:A(x)B(x)=∑k≥0(∑i+j=kaibj)xiA(x)B(x)=\sum_{k\ge 0}(\sum_{i+j=k} a_ib_j)x^iA(x)B(x)=∑k≥0​(∑i+j=k​ai​bj​)xi

我们发现,乘法和多项式乘法有共同之处

# 形式幂级数

记形式幂级数(或多项式)A(x)A(x)A(x) 的 xnx^nxn 项的系数为 [xn]A(x)[x^n]A(x)[xn]A(x)

形式幂级数的本质是序列,幂级数的本质是极限

# 形式幂级数的逆元

  • 形式幂级数 A(x)A(x)A(x) 的逆元:A(x)B(x)=1A(x)B(x)=1A(x)B(x)=1
  • 逆元存在的条件:[x0]A(x)≠0[x^0]A(x)\ne 0[x0]A(x)​=0

常见的逆:

  • A(x)=1+x+x2+⋯A(x)=1+x+x^2+\cdotsA(x)=1+x+x2+⋯ 的逆元为 B(x)=1−xB(x)=1-xB(x)=1−x
  • A(x)=1+ax+axx2+⋯A(x)=1+ax+a^xx^2+\cdotsA(x)=1+ax+axx2+⋯ 的逆元为 B(x)=1−axB(x)=1-axB(x)=1−ax
  • A(x)=Ck−10+Ck1x+Ck+12x2+Ck+13x3+⋯A(x)=C_{k-1}^0+C_{k}^1x+C_{k+1}^2x^2+C_{k+1}^3x^3+\cdotsA(x)=Ck−10​+Ck1​x+Ck+12​x2+Ck+13​x3+⋯ 的逆元为 B(x)=(1−x)kB(x)=(1-x)^kB(x)=(1−x)k,即 A(x)=1(1−x)k=∑i≥0Ci+k−1ixiA(x)=\frac{1}{(1-x)^k}=\sum_{i\ge 0}C_{i+k-1}^i x^iA(x)=(1−x)k1​=∑i≥0​Ci+k−1i​xi

# 形式幂级数的求导

假设 f(x)=a0+a1x+a2x2+⋯+anxn+⋯f(x)=a_0+a_1x+a_2x^2+\cdots+a_nx^n+\cdotsf(x)=a0​+a1​x+a2​x2+⋯+an​xn+⋯

定义 f(x)f(x)f(x) 的导数为 a1+2a2x+⋯+(n+1)an+1xn+⋯a_1+2a_2x+\cdots+(n+1)a_{n+1}x^n+\cdotsa1​+2a2​x+⋯+(n+1)an+1​xn+⋯ 记作 f′(x)f'(x)f′(x) 或 df(x)dx\frac{df(x)}{dx}dxdf(x)​

# 形式幂级数的积分

假设 f(x)=a0+a1x+a2x2+⋯+anxn+⋯f(x)=a_0+a_1x+a_2x^2+\cdots+a_nx^n+\cdotsf(x)=a0​+a1​x+a2​x2+⋯+an​xn+⋯

定义 f(x)f(x)f(x) 的积分为 a0x+a12x2+⋯+an−1nxn+⋯a_0x+\frac{a_1}{2}x^2+\cdots+\frac{a_{n-1}}{n}x^n+\cdotsa0​x+2a1​​x2+⋯+nan−1​​xn+⋯ 记作 ∫f(x)dx\int f(x)dx∫f(x)dx

# 形式幂级数的复合

假设 f(x)=a1x+⋯+anxn+⋯f(x)=a_1x+\cdots+a_nx^n+\cdotsf(x)=a1​x+⋯+an​xn+⋯,g(x)=b0+b1x+⋯+bnxn+⋯g(x)=b_0+b_1x+\cdots+b_nx^n+\cdotsg(x)=b0​+b1​x+⋯+bn​xn+⋯

ggg 复合 fff 定义为 c0+c1x+⋯+cnxn+⋯c_0+c_1x+\cdots+c_nx^n+\cdotsc0​+c1​x+⋯+cn​xn+⋯,满足 c0=b0,cn=∑k=1nbk∑i1+i2+⋯+ik=nai1ai2⋯aikc_0=b_0,c_n=\sum_{k=1}^n b_k\sum_{i_1+i_2+\cdots+i_k=n}a_{i_1}a_{i_2}\cdots a_{i_k}c0​=b0​,cn​=∑k=1n​bk​∑i1​+i2​+⋯+ik​=n​ai1​​ai2​​⋯aik​​,记为 g(f(x))g(f(x))g(f(x))

image-20241031172927051

# 形式幂级数的其他运算

  • exp⁡(x)=∑n≥01n!xn\exp(x)=\sum_{n\ge 0} \frac{1}{n!}x^nexp(x)=∑n≥0​n!1​xn
  • ln⁡(1+x)=∑n≥1(−1)n+1nxn\ln(1+x)=\sum_{n\ge 1}\frac{(-1)^{n+1}}{n}x^nln(1+x)=∑n≥1​n(−1)n+1​xn
  • 设形式幂级数 f(x)f(x)f(x) 满足 [x0]f(x)=0[x^0]f(x)=0[x0]f(x)=0 由此可以定义 exp⁡(f(x))\exp(f(x))exp(f(x)) 和 ln⁡(f(x)+1)\ln(f(x)+1)ln(f(x)+1),或者可以定义 [x0]f(x)=1[x^0]f(x)=1[x0]f(x)=1 则可以计算 ln⁡(f(x))\ln(f(x))ln(f(x))

image-20241031173838965

# 常生成函数

一个数列 {an}\{a_n\}{an​} 对应的常数生成函数为 A(x)=∑n≥0anxnA(x)=\sum_{n\ge 0} a_nx^nA(x)=∑n≥0​an​xn

例: 有两种物品,其中取 iii 个第 111 种物品的方案数为 aia_iai​,取 jjj 个第二种物体的方案数为 bjb_jbj​,求取 kkk 个物体的方案数

设 A(x)=∑i≥0aixi,B(x)=∑j≥0bjxjA(x)=\sum_{i\ge 0} a_ix^i, B(x)=\sum_{j\ge 0} b_jx^jA(x)=∑i≥0​ai​xi,B(x)=∑j≥0​bj​xj

答案为 C(x)=A(x)B(x)C(x)=A(x)B(x)C(x)=A(x)B(x)

# 递推关系

斐波那契数列满足 a0=0,a1=1,an=an−1+an−2(n≥2)a_0=0,a_1=1,a_n=a_{n-1}+a_{n-2}(n\ge 2)a0​=0,a1​=1,an​=an−1​+an−2​(n≥2),求其生成函数

设 A(x)=∑n≥0anxnA(x)=\sum_{n\ge 0} a_nx^nA(x)=∑n≥0​an​xn

A(x)=a0+a1x+a2x2+⋯=0+x+(a0+a1)x2+(a1+a2)x3+⋯+(an−2+an−1)xn+⋯=x+(a1x2+a2x3+a3x4+⋯)+(a1x3+a2x4+⋯)=x+xA(x)+x2A(x) \begin{aligned} A(x)&=a_0+a_1x+a_2x^2+\cdots\\ &=0+x+(a_0+a_1)x^2+(a_1+a_2)x^3+\cdots+(a_{n-2}+a_{n-1})x^n+\cdots\\ &=x+(a_1x^2+a_2x^3+a_3x^4+\cdots)+(a_1x^3+a_2x^4+\cdots)\\ &=x+xA(x)+x^2A(x)\\ \end{aligned} A(x)​=a0​+a1​x+a2​x2+⋯=0+x+(a0​+a1​)x2+(a1​+a2​)x3+⋯+(an−2​+an−1​)xn+⋯=x+(a1​x2+a2​x3+a3​x4+⋯)+(a1​x3+a2​x4+⋯)=x+xA(x)+x2A(x)​

解得 A(x)=x1−x−x2A(x)=\frac{x}{1-x-x^2}A(x)=1−x−x2x​

我们可以通过这个常生成函数来求数列的第 nnn 项

把分数拆开,有:

A(x)=x1−x−x2=x(c1−ax+d1−bx) A(x)=\frac{x}{1-x-x^2}=x(\frac{c}{1-ax}+\frac{d}{1-bx}) A(x)=1−x−x2x​=x(1−axc​+1−bxd​)

那么: [xn]A(x)=c⋅an+d⋅bn[x^n]A(x)=c\cdot a^{n}+d\cdot b^{n}[xn]A(x)=c⋅an+d⋅bn

上面的 a,b,c,da,b,c,da,b,c,d 可以使用待定系数法求解

# 指数生成函数

一个数列 {an}\{a_n\}{an​} 对应的指数生成函数为 A(x)=∑n≥0anxnn!A(x)=\sum\limits_{n\ge 0} a_n\frac{x^n}{n!}A(x)=n≥0∑​an​n!xn​

有两个物体,其中取 iii 个第 111 种物品的方案数为 aia_iai​,取 jjj 个第二种物体的方案数为 bjb_jbj​,求取 kkk 个物体并排成一列的方案数

设 A(x)=∑i≥0aixii!,B(x)=∑j≥0bjxjj!A(x)=\sum_{i\ge 0} a_i\frac{x^i}{i!}, B(x)=\sum_{j\ge 0} b_j\frac{x^j}{j!}A(x)=∑i≥0​ai​i!xi​,B(x)=∑j≥0​bj​j!xj​

ck=∑i=0k(ki)aibk−i=∑i=0kk!i!(k−i)!aibk−ickk!=∑i=0kaii!bk−i(k−i)!C(x)=A(x)B(x) \begin{aligned} c_k&=\sum_{i=0}^k\binom{k}{i}a_ib_{k-i}\\ &=\sum\limits_{i=0}^k\frac{k!}{i!(k-i)!}a_ib_{k-i}\\ \frac{c_k}{k!}&=\sum\limits_{i=0}^k\frac{a_i}{i!}\frac{b_{k-i}}{(k-i)!}\\ C(x)&=A(x)B(x) \end{aligned} ck​k!ck​​C(x)​=i=0∑k​(ik​)ai​bk−i​=i=0∑k​i!(k−i)!k!​ai​bk−i​=i=0∑k​i!ai​​(k−i)!bk−i​​=A(x)B(x)​

所以答案为 C(x)=A(x)B(x)C(x)=A(x)B(x)C(x)=A(x)B(x)

image.png
  • exp⁡(x)=1+x+x22!+⋯=∑n≥0xnn!\exp(x)=1+x+\frac{x^2}{2!}+\cdots=\sum\limits_{n\ge 0} \frac{x^n}{n!}exp(x)=1+x+2!x2​+⋯=n≥0∑​n!xn​
  • exp⁡(nx)=1+nx+n2x22!+⋯=∑n≥0nnxnn!\exp(nx)=1+nx+\frac{n^2x^2}{2!}+\cdots=\sum\limits_{n\ge 0} \frac{n^nx^n}{n!}exp(nx)=1+nx+2!n2x2​+⋯=n≥0∑​n!nnxn​

使用 exp⁡\expexp 函数就可以实现生成函数之间的运算了,比如 exp⁡(a)exp⁡(b)=exp⁡(a+b)\exp(a)\exp(b)=\exp(a+b)exp(a)exp(b)=exp(a+b)

# FFT

朴素多项式乘法,求逆,开根号等的复杂度为 O(n2)O(n^2)O(n2)

FFT / NTT 可以 O(nlog⁡n)O(n\log n)O(nlogn) 内实现两个 nnn 次多项式的乘积

# 多项式的表示形式

假设 f(x)f(x)f(x) 是一个 nnn 次多项式,则 f(x)f(x)f(x) 的系数表示为 f(x)=anxn+an−1xn−1+⋯+a0f(x)=a_nx^n+a_{n-1}x^{n-1}+\cdots+a_0f(x)=an​xn+an−1​xn−1+⋯+a0​

则 f(x)f(x)f(x) 的点值表示为 (x0,f(x0)),(x1,f(x1)),⋯,(xn,f(xn))(x_0,f(x_0)),(x_1,f(x_1)),\cdots,(x_n,f(x_n))(x0​,f(x0​)),(x1​,f(x1​)),⋯,(xn​,f(xn​))

那么也就是说 n+1n+1n+1 个点值可以表示一个 nnn 次多项式

在点值表示下 nnn 次多项式的乘法复杂度为 O(n)O(n)O(n)

# 复数与单位根

复数的指数形式

a+bi=reiθa+b_i=re^{i\theta}a+bi​=reiθ,其中 t=a2+b2t=\sqrt{a^2+b^2}t=a2+b2​,tan(θ)=batan(\theta)=\frac{b}{a}tan(θ)=ab​

单位根

xn=1x^n=1xn=1 在复数域上的根称为 nnn 次单位根。nnn 次单位根有 nnn 个,形式为 wnk=ei2kπnw^k_n=e^{i\frac{2k\pi}{n}}wnk​=ein2kπ​

单位根的性质:

  • wnk=w2n2kw^k_n=w^{2k}_{2n}wnk​=w2n2k​
  • w2nk+n=−w2nkw^{k+n}_{2n}=-w^{k}_{2n}w2nk+n​=−w2nk​

# 快速傅里叶变换

DFT(离散傅里叶变换)

将多项式 A(x)=a0+a1x+⋯+an−1xn−1A(x)=a_0+a_1x+\cdots+a_{n-1}x^{n-1}A(x)=a0​+a1​x+⋯+an−1​xn−1 转化为其点值形式 (wnk,A(wnk)),(k=0,1,⋯,n−1)(w_n^k,A(w_n^k)),(k=0,1,\cdots,n-1)(wnk​,A(wnk​)),(k=0,1,⋯,n−1)

这里如何求这个 A(wnk)=dkA(w_n^k)=d_kA(wnk​)=dk​

这里有傅里叶变换的公式:

dk=∑i=0n−1ai×wnik d_k=\sum\limits_{i=0}^{n-1}a_i\times w_n^{ik} dk​=i=0∑n−1​ai​×wnik​

由于这个式子是一个线性的,所以我们能写成矩阵的形式

(d0d1d2⋮dn−1)=(wn0×0wn0×1wn0×2⋯wn0×(n−1)wn1×0wn1×1wn1×2⋯wn1×(n−1)wn2×0wn2×1wn2×2⋯wn2×(n−1)⋮⋮⋮⋱⋮wn(n−1)×0wn(n−1)×1wn(n−1)×2⋯wn(n−1)×(n−1))(a0a1a2⋮an−1) \begin{pmatrix} d_0\\ d_1\\ d_2\\ \vdots\\d_{n-1} \end{pmatrix} = \begin{pmatrix} w_{n}^{0\times0} & w_{n}^{0\times 1} & w_{n}^{0\times 2} & \cdots & w_{n}^{0\times (n-1)}\\ w_{n}^{1\times0} & w_{n}^{1\times 1} & w_{n}^{1\times 2} & \cdots & w_{n}^{1\times (n-1)}\\ w_{n}^{2\times0} & w_{n}^{2\times 1} & w_{n}^{2\times 2} & \cdots & w_{n}^{2\times (n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ w_{n}^{(n-1)\times0} & w_{n}^{(n-1)\times 1} & w_{n}^{(n-1)\times 2} & \cdots & w_{n}^{(n-1)\times (n-1)} \end{pmatrix} \begin{pmatrix} a_0\\ a_1\\ a_2\\ \vdots\\a_{n-1} \end{pmatrix} ⎝⎜⎜⎜⎜⎜⎜⎛​d0​d1​d2​⋮dn−1​​⎠⎟⎟⎟⎟⎟⎟⎞​=⎝⎜⎜⎜⎜⎜⎜⎜⎛​wn0×0​wn1×0​wn2×0​⋮wn(n−1)×0​​wn0×1​wn1×1​wn2×1​⋮wn(n−1)×1​​wn0×2​wn1×2​wn2×2​⋮wn(n−1)×2​​⋯⋯⋯⋱⋯​wn0×(n−1)​wn1×(n−1)​wn2×(n−1)​⋮wn(n−1)×(n−1)​​⎠⎟⎟⎟⎟⎟⎟⎟⎞​⎝⎜⎜⎜⎜⎜⎜⎛​a0​a1​a2​⋮an−1​​⎠⎟⎟⎟⎟⎟⎟⎞​

但是我们暴力求 {d}\{d\}{d} 也是 O(n2)O(n^2)O(n2) 的,现在考虑一种分治做法

我们有:A(x)=a0+a1x+⋯+an−1xn−1A(x)=a_0+a_1x+\cdots+a_{n-1}x^{n-1}A(x)=a0​+a1​x+⋯+an−1​xn−1

把 A(x)A(x)A(x) 拆成奇数项和偶数项:A(x)=(a0+a2x2+⋯+an−2xn−2)+(a1x+a3x3+a5x5+⋯+an−1xn−1)A(x)=(a_0+a_2x^2+\cdots+a_{n-2}x^{n-2})+(a_1x+a_3x^3+a_5x^5+\cdots+a_{n-1}x^{n-1})A(x)=(a0​+a2​x2+⋯+an−2​xn−2)+(a1​x+a3​x3+a5​x5+⋯+an−1​xn−1)

设

B(x)=a0+a2x+⋯+an−2xn/2−1C(x)=a1+a3x+⋯+an−1xn/2−1 \begin{aligned} B(x)=a_0+a_2x+\cdots+a_{n-2}x^{n/2-1}\\ C(x)=a_1+a_3x+\cdots+a_{n-1}x^{n/2-1} \end{aligned} B(x)=a0​+a2​x+⋯+an−2​xn/2−1C(x)=a1​+a3​x+⋯+an−1​xn/2−1​

则 A(x)=B(x2)+xC(x2)A(x)=B(x^2)+xC(x^2)A(x)=B(x2)+xC(x2)

  • 当 0≤k<n/20\le k < n/20≤k<n/2 时
A(wnk)=B(wn2k)+wnkC(wn2k)=B(wn/2k)+wnkC(wn/2k) \begin{aligned} A(w^k_{n})&=B(w^{2k}_n)+w^k_nC(w_n^{2k})\\ &=B(w^{k}_{n/2})+w^{k}_nC(w^k_{n/2}) \end{aligned} A(wnk​)​=B(wn2k​)+wnk​C(wn2k​)=B(wn/2k​)+wnk​C(wn/2k​)​
  • 当 n/2<kn/2 < kn/2<k 时

不妨把 kkk 减小 n/2n/2n/2 继续把 kkk 控制在 0≤k<n/20\le k < n/20≤k<n/2 的范围内

A(wnk+n/2)=B(wn2k+n)+wnk+n/2C(wn2k+n)=B(wn2k)+wnk+n/2C(wn2k)=B(wn/2k)+wnk+n/2C(wn/2k)=B(wn/2k)−wnkC(wn/2k) \begin{aligned} A(w^{k+n/2}_{n})&=B(w^{2k+n}_n)+w^{k+n/2}_{n}C(w^{2k+n}_n)\\ &=B(w^{2k}_n)+w^{k+n/2}_{n}C(w^{2k}_n)\\ &=B(w_{n/2}^{k})+w_n^{k+n/2}C(w^{k}_{n/2})\\ &=B(w_{n/2}^k)-w_n^kC(w^k_{n/2}) \end{aligned} A(wnk+n/2​)​=B(wn2k+n​)+wnk+n/2​C(wn2k+n​)=B(wn2k​)+wnk+n/2​C(wn2k​)=B(wn/2k​)+wnk+n/2​C(wn/2k​)=B(wn/2k​)−wnk​C(wn/2k​)​

IDFT(逆离散傅里叶变换)

将多项式的点值表示 (wnk,bk)(w_n^k,b_k)(wnk​,bk​), (k=0,1,⋯,n−1)(k=0,1,\cdots,n-1)(k=0,1,⋯,n−1) 转化为其系数表示 A(x)=a0+a1x+⋯+an−1xn−1A(x)=a_0+a_1x+\cdots+a_{n-1}x^{n-1}A(x)=a0​+a1​x+⋯+an−1​xn−1

我直接给出逆变换的公式 ai=1n∑k=0n−1bkwn−ika_i=\frac{1}{n}\sum\limits_{k=0}^{n-1}b_kw_n^{-ik}ai​=n1​k=0∑n−1​bk​wn−ik​

但是现在要思考如何理解这个公式

对于上面那个 DFT 的变换的矩阵

AΩ=D A\Omega=D AΩ=D

现在相当于已知 Ω\OmegaΩ 和 DDD 求 AAA,那么只需要求出 Ω−1\Omega^{-1}Ω−1 即可

尝试构造 Ω−1\Omega^{-1}Ω−1,我们尝试共轭矩阵 Ω‾\overline{\Omega}Ω

Ω⋅Ω‾=P=(wn0×0wn0×1wn0×2⋯wn0×(n−1)wn1×0wn1×1wn1×2⋯wn1×(n−1)wn2×0wn2×1wn2×2⋯wn2×(n−1)⋮⋮⋮⋱⋮wn(n−1)×0wn(n−1)×1wn(n−1)×2⋯wn(n−1)×(n−1))(wn−0×0wn−0×1wn−0×2⋯wn−0×(n−1)wn−1×0wn−1×1wn−1×2⋯wn−1×(n−1)wn−2×0wn−2×1wn−2×2⋯wn−2×(n−1)⋮⋮⋮⋱⋮wn−(n−1)×0wn−(n−1)×1wn−(n−1)×2⋯wn−(n−1)×(n−1)) \begin{aligned} \Omega \cdot \overline{\Omega}=P= \begin{pmatrix} w_{n}^{0\times0} & w_{n}^{0\times 1} & w_{n}^{0\times 2} & \cdots & w_{n}^{0\times (n-1)}\\ w_{n}^{1\times0} & w_{n}^{1\times 1} & w_{n}^{1\times 2} & \cdots & w_{n}^{1\times (n-1)}\\ w_{n}^{2\times0} & w_{n}^{2\times 1} & w_{n}^{2\times 2} & \cdots & w_{n}^{2\times (n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ w_{n}^{(n-1)\times0} & w_{n}^{(n-1)\times 1} & w_{n}^{(n-1)\times 2} & \cdots & w_{n}^{(n-1)\times (n-1)} \end{pmatrix} \begin{pmatrix} w_{n}^{-0\times0} & w_{n}^{-0\times 1} & w_{n}^{-0\times 2} & \cdots & w_{n}^{-0\times (n-1)}\\ w_{n}^{-1\times0} & w_{n}^{-1\times 1} & w_{n}^{-1\times 2} & \cdots & w_{n}^{-1\times (n-1)}\\ w_{n}^{-2\times0} & w_{n}^{-2\times 1} & w_{n}^{-2\times 2} & \cdots & w_{n}^{-2\times (n-1)}\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ w_{n}^{-(n-1)\times0} & w_{n}^{-(n-1)\times 1} & w_{n}^{-(n-1)\times 2} & \cdots & w_{n}^{-(n-1)\times (n-1)} \end{pmatrix} \end{aligned} Ω⋅Ω=P=⎝⎜⎜⎜⎜⎜⎜⎜⎛​wn0×0​wn1×0​wn2×0​⋮wn(n−1)×0​​wn0×1​wn1×1​wn2×1​⋮wn(n−1)×1​​wn0×2​wn1×2​wn2×2​⋮wn(n−1)×2​​⋯⋯⋯⋱⋯​wn0×(n−1)​wn1×(n−1)​wn2×(n−1)​⋮wn(n−1)×(n−1)​​⎠⎟⎟⎟⎟⎟⎟⎟⎞​⎝⎜⎜⎜⎜⎜⎜⎜⎛​wn−0×0​wn−1×0​wn−2×0​⋮wn−(n−1)×0​​wn−0×1​wn−1×1​wn−2×1​⋮wn−(n−1)×1​​wn−0×2​wn−1×2​wn−2×2​⋮wn−(n−1)×2​​⋯⋯⋯⋱⋯​wn−0×(n−1)​wn−1×(n−1)​wn−2×(n−1)​⋮wn−(n−1)×(n−1)​​⎠⎟⎟⎟⎟⎟⎟⎟⎞​​

观察答案矩阵 PPP 的第 iii 行 第 iii 列

P=∑k=0n−1wni×kwn−k×j=∑k=0n−1wn(i−j)×k P=\sum\limits_{k=0}^{n-1}w_n^{i\times k} w_n^{-k\times j}=\sum\limits_{k=0}^{n-1}w_n^{(i-j)\times k} P=k=0∑n−1​wni×k​wn−k×j​=k=0∑n−1​wn(i−j)×k​

我们发现这是一个公差为 wni−jw_n^{i-j}wni−j​ 的等差数列求和,根据等差数列求和公式

∑k=0n−1wn(i−j)×k={n,i=j1−(wni−j)n1−wni−j=0,i≠j \sum\limits_{k=0}^{n-1}w_n^{(i-j)\times k}= \begin{cases} n, \ i=j\\ \frac{1-(w_n^{i-j})^n}{1-w_n^{i-j}}=0, \ i\ne j\\ \end{cases} k=0∑n−1​wn(i−j)×k​={n, i=j1−wni−j​1−(wni−j​)n​=0, i​=j​

得出答案矩阵为:

(n00⋯00n0⋯000n⋯0⋮⋮⋮⋱⋮000⋯n)=nI \begin{pmatrix} n & 0 & 0 & \cdots & 0\\ 0 & n & 0 & \cdots & 0\\ 0 & 0 & n & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots\\ 0 & 0 & 0 & \cdots & n \end{pmatrix}=nI ⎝⎜⎜⎜⎜⎜⎜⎛​n00⋮0​0n0⋮0​00n⋮0​⋯⋯⋯⋱⋯​000⋮n​⎠⎟⎟⎟⎟⎟⎟⎞​=nI

Ω⋅Ω‾=nI\Omega \cdot \overline{\Omega}=nIΩ⋅Ω=nI, Ω−1=1nΩ‾\Omega^{-1}=\frac{1}{n}\overline{\Omega}Ω−1=n1​Ω

这样就可以求出 D=1nΩ‾AD=\frac{1}{n}\overline{\Omega} AD=n1​ΩA,也就是我们上面的公式

ai=1n∑k=0n−1bkwn−ik a_i=\frac{1}{n}\sum\limits_{k=0}^{n-1}b_kw_n^{-ik} ai​=n1​k=0∑n−1​bk​wn−ik​

现在我们已知了 DFT 和 IDFT 的公式,那么我们就可以进行 FFT 了

image.png

直接来看代码实现

首先,我们需要一个复数类,尽管 C++ 有复数类,常数太大了

struct Complex {
    double x, y;
    Complex (double x = 0, double y = 0) : x(x), y(y) {}
};

Complex operator + (Complex a, Complex b) { return Complex(a.x + b.x, a.y + b.y); }
Complex operator - (Complex a, Complex b) { return Complex(a.x - b.x, a.y - b.y); }
Complex operator * (Complex a, Complex b) { return Complex(a.x * b.x - a.y * b.y, a.x * b.y + a.y * b.x); }
1
2
3
4
5
6
7
8

递归实现 FFT

#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1 << 22;
const double eps = 1e-6, pi = acos(-1);

complex<double> a[MAXN], b[MAXN], c[MAXN];
int n, m;

void FFT(complex<double> *a, int n, int inv) { // inv 为 1 时为 FFT, inv 为 -1 时为 IFFT
    if (n == 1) return;
    int mid = n >> 1;
    complex<double> A1[mid + 1], A2[mid + 1];
    for (int i = 0; i <= n; i += 2) {
        A1[i >> 1] = a[i];
        A2[i >> 1] = a[i + 1];
    }
    FFT(A1, mid, inv); FFT(A2, mid, inv);
    complex<double> w0(1, 0), wn(cos(2 * pi / n), inv * sin(2 * pi / n));
    for (int i = 0; i < mid; i++, w0 *= wn) {
        a[i] = A1[i] + w0 * A2[i];
        a[i + mid] = A1[i] - w0 * A2[i];
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i <= n; i++) {double x; scanf("%lf", &x); a[i].real(x);}
    for (int i = 0; i <= m; i++) {double x; scanf("%lf", &x); b[i].real(x);}
    int len = 1 << max((int)ceil(log2(n + m)), 1); //由于FFT需要项数为2的整数次方倍,所以多项式的次数len为第一个大于 n+m 的二的正整数次方
    FFT(a, len, 1); FFT(b, len, 1);
    for (int i = 0; i < len; i++) c[i] = a[i] * b[i];
    FFT(c, len, -1);
    for (int i = 0; i <= n + m; i++)
        printf("%.0f ",(c[i].real() / len + eps));
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 蝴蝶变换

image-20241011235630473

观察原序列和后序列的二进制之后,惊奇的发现,其实际上就是把二进制翻转了,我们可以用 O(32n)O(32n)O(32n) 来实现

实际上可以用 O(n)O(n)O(n) 的递推式来实现,定义 R(n)R(n)R(n) 表示 nnn 二进制反转后对应的值,有递推式:

R(n)=R(n/2)+(n&1)×n2 R(n)=R(n/2)+(n\&1)\times\frac{n}{2} R(n)=R(n/2)+(n&1)×2n​

通过这个递推式能求出 R(n)R(n)R(n)

void change(complex<double> A[], int n) {
    for (int i = 0; i < n; i++)
        R[i] = (R[i >> 1] >> 1) + ((i & 1) ? n >> 1 : 0);
    for (int i = 0; i < n; i++)
        if (i < R[i]) swap(A[i], A[R[i]]); // 只需要换一次
}
1
2
3
4
5
6

然后有了这个思路,就可以直接构造出最后一层的下标然后从下往上模拟递归合并的过程了

image.png
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 1 << 22;
const double eps = 1e-6, pi = acos(-1);

complex<double> a[MAXN], b[MAXN], c[MAXN];
int R[MAXN];
int n, m;

void change(complex<double> A[], int n) {
    for (int i = 0; i < n; i++)
        R[i] = (R[i >> 1] >> 1) + ((i & 1) ? n >> 1 : 0);
    for (int i = 0; i < n; i++)
        if (i < R[i]) swap(A[i], A[R[i]]);
}

void FFT(complex<double> *a, int n, int inv) { // inv 为 1 时为 FFT, inv 为 -1 时为 IFFT
    change(a, n);
    for (int m = 2; m <= n; m <<= 1) {
        complex<double> w1(cos(2 * pi / m), inv * sin(2 * pi / m));
        for (int i = 0; i < n; i += m) {
            complex<double> wk(1, 0);
            for (int j = 0; j < m / 2; j++, wk *= w1) {
                auto x = a[i + j], y = wk * a[i + j + m / 2];
                a[i + j] = x + y; a[i + j + m / 2] = x - y;
            }
        }
    }
}

int main() {
    scanf("%d %d", &n, &m);
    for (int i = 0; i <= n; i++) {double x; scanf("%lf", &x); a[i].real(x);}
    for (int i = 0; i <= m; i++) {double x; scanf("%lf", &x); b[i].real(x);}
    int len = 1 << max((int)ceil(log2(n + m)), 1); //由于FFT需要项数为2的整数次方倍,所以多项式的次数len为第一个大于 n+m 的二的正整数次方
    FFT(a, len, 1); FFT(b, len, 1);
    for (int i = 0; i < len; i++) c[i] = a[i] * b[i];
    FFT(c, len, -1);
    for (int i = 0; i <= n + m; i++)
        printf("%.0f ",(c[i].real() / len + eps));
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# NTT

# 原根

欧拉定理

若正整数 m,am,am,a,满足 gcd⁡(a,m)=1\gcd(a,m)=1gcd(a,m)=1,则 aφ(n)≡1(modm)a^{\varphi (n)}\equiv 1 \pmod{m}aφ(n)≡1 (modm)

阶

若正整数 m,am,am,a,满足 gcd⁡(a,m)=1\gcd(a,m)=1gcd(a,m)=1,则 ak≡1(modm)a^k\equiv 1 \pmod{m}ak≡1 (modm) 的最小正整数 kkk 称为 aaa 对模 mmm 的阶,记作 δm(a)\delta_m(a)δm​(a)

若 δm(a)=φ(m)\delta_m(a)=\varphi(m)δm​(a)=φ(m),则称 aaa 为 mmm 的一个原根

阶的性质

假设 (a,m)=1,δ=δm(a)(a,m)=1,\delta=\delta_m(a)(a,m)=1,δ=δm​(a),则

  • a0,a1,⋯,aδ−1a^0,a^1,\cdots,a^{\delta -1}a0,a1,⋯,aδ−1 在模 mmm 意义下两两不同
  • aγ≡aγ′(modm)⇔γ≡γ′(modm)a^{\gamma}\equiv a^{\gamma'}\pmod{m}\Leftrightarrow \gamma\equiv \gamma'\pmod{m}aγ≡aγ′ (modm)⇔γ≡γ′ (modm)
  • δ∣φ(m)\delta | \varphi(m)δ∣φ(m)

原根的存在与判定

只有模 2,4,pa,2pa2,4,p^a,2p^a2,4,pa,2pa 存在原根(ppp 是奇质数)

原根的判定定理

设 m>1m>1m>1,ggg 为正整数且 (g,m)=1(g,m)=1(g,m)=1。则 ggg 是 mmm 的原根当且仅当对于任意 φ(m)\varphi(m)φ(m) 的质因子 qiq_iqi​,gφ(m)qi≢1(modm)g^{\frac{\varphi(m)}{q_i}}\not \equiv 1\pmod{m}gqi​φ(m)​​≡1 (modm)

如何寻找原根,假设这里我们需要寻找 ppp 的原根,那么有 g0,g1,⋯,gφ(p)−1g^0,g^1,\cdots,g^{\varphi(p)-1}g0,g1,⋯,gφ(p)−1 在模 ppp 意义下各不相同,如果 ppp 是一个质数,那么这里有 φ(p)=p−1\varphi(p)=p-1φ(p)=p−1

一个数原根的个数为 φ(φ(p))\varphi(\varphi(p))φ(φ(p)) 但是第一个原根往往不是特别大,所以从小到大枚举 rtrtrt 然后 O(p)O(p)O(p) 去 check

若 rtrtrt 不是原根,那么一定存在 0≤i<j≤φ(n)−10\le i < j \le \varphi(n)-10≤i<j≤φ(n)−1 使得 gi≡gj(modp)g^i\equiv g^j \pmod{p}gi≡gj (modp) 那么有 gj−i≡1(modp)g^{j-i}\equiv 1\pmod{p}gj−i≡1 (modp) ,所以说如果出现一个 0<d=j−i<φ(p)0<d=j-i<\varphi(p)0<d=j−i<φ(p) 使得 gd≡1(modp)g^d\equiv 1\pmod{p}gd≡1 (modp),那么就说明 rtrtrt 不是原根

int rt = 1; // P 是一个质数
while (true) {
    bool ok = true;
    int v = 1;
    for (int i = 1; i < P - 1; i++) {
        v = v * rt % P;
        if (v == 1) {
            ok = false;
            break;
        }
    }
    if (ok) break;
    rt += 1;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

设 d=j−id=j-id=j−i,又有 gφ(n)≡1(modp)g^{\varphi(n)}\equiv 1\pmod{p}gφ(n)≡1 (modp),所以有 d∣φ(n)d|\varphi(n)d∣φ(n)

于是,我们只需要预处理出 φ(n)\varphi(n)φ(n) 的的因数 {e}\{e\}{e},对于一个 rtrtrt 如果存在一个 rtei≡1(modp)rt^{e_i}\equiv 1\pmod{p}rtei​≡1 (modp) 那么 rtrtrt 就不是原根

指标

对于质数 ppp,假设 ggg 是 ppp 的一个原根,则 g0,g1,gp−2g^0,g^1,g^{p-2}g0,g1,gp−2 在模 ppp 意义下是 1,2,⋯,p−11,2,\cdots,p-11,2,⋯,p−1 的一个排列。假设对于 1≤x≤p−11\le x \le p-11≤x≤p−1 有 gc≡x(modp)g^c\equiv x \pmod{p}gc≡x (modp) 则称 xxx 的指标为 ccc,记作 ind(x)=c\text{ind}(x)=cind(x)=c

指标有着非常优秀的性质,也被称为离散对数:∀1≤x,y<p,ind(xy)≡ind(x)+ind(y)(modφ(p)))\forall 1\le x,y<p, \text{ind}(xy)\equiv \text{ind}(x)+\text{ind}(y)\pmod{\varphi(p))}∀1≤x,y<p,ind(xy)≡ind(x)+ind(y) (modφ(p)))

如何求一个 ind(x)\text{ind}(x)ind(x) 可以使用 BSGS 算法

求所有的 ind(x)\text{ind(x)}ind(x) 可以使用 O(n)O(n)O(n) 的递推

vector<ll> lg(P, 0);
for (int i = 0, v = 1; i < P - 1; i++) {
    lg[v] = i;
    v = v * rt % P;
}
1
2
3
4
5

# NTT 实现

假设质数 p=r2l+1p=r2^l+1p=r2l+1 ,ggg 是 ppp 的原根,和 FFT 类似,我们用 gn=gp−1ng_n=g^{\frac{p-1}{n}}gn​=gnp−1​ 代替 wnw_nwn​

我们发现,这样子去选取 gng_ngn​ 一样满足一些性质:

  • g2n2k≡gnk(mod p),(2n≤2l)g_{2n}^{2k} \equiv g_n^k \ (\text{mod}\ p), \ (2n \leq 2^l)g2n2k​≡gnk​ (mod p), (2n≤2l)
  • g2nn≡−1(mod p),(2n≤2l)g_{2n}^n \equiv -1 \ (\text{mod}\ p), \ (2n \leq 2^l)g2nn​≡−1 (mod p), (2n≤2l)
  • ∑k=0n−1gnikgn−kj≡{n,if i=j0,otherwise\sum_{k=0}^{n-1} g_n^{ik} g_n^{-kj} \equiv \begin{cases} n,\text{if} \ i = j \\ 0, \text{otherwise} \end{cases}∑k=0n−1​gnik​gn−kj​≡{n,if i=j0,otherwise​

和 FFT 类似,只不过这里用原根来替换单位根,来进行一个模意义下的运算,FFT 中的 DFT,IDFT,依然成立

  • NTT 的优点:快,精确
  • NTT 的限制:模数需要是满足 p=r2l+1p=r2^l+1p=r2l+1 的质数 ppp,

下面有些常见的模数:

  • 65537=216+1,g=365537=2^{16}+1,g=365537=216+1,g=3
  • 998244353=119×223+1,g=3998244353=119\times 2^{23}+1,g=3998244353=119×223+1,g=3
  • 1004535809=479×221+1,g=31004535809=479\times2^{21}+1,g=31004535809=479×221+1,g=3
  • 4179340454199820289=29×257+1,g=34179340454199820289=29\times 2^{57}+1,g=34179340454199820289=29×257+1,g=3

非递归的 NTT

//NTT

int rev[MAXN], limit, bit;

void NTT (vector<ll> &a, int op) {
    for (int i = 0; i < limit; i++)
        if (i < rev[i]) swap(a[i], a[rev[i]]);
    
    for (int m = 2; m <= limit; m <<= 1) {
        ll gn = qpow(3, (MOD - 1) / m); 
        if (op == -1) gn = qpow(gn, MOD - 2);
        for (int i = 0; i < limit; i += m) {
            ll gk = 1;
            for (int j = 0; j < m / 2; j++) {
                ll x = a[i + j], y = gk * a[i + j + m / 2] % MOD;
                a[i + j] = (x + y) % MOD;
                a[i + j + m / 2] = (x - y + MOD) % MOD;
                gk = gk * gn % MOD;
            }
        }
    }
}

void convolution(vector<ll> A, vector<ll> B, vector<ll> &C) {
    int n = A.size() - 1, m = B.size() - 1;
    limit = 1, bit = 0;
    while (limit <= n + m) limit <<= 1, bit += 1;
    for (int i = 0; i < limit; i++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));

    A.resize(limit), B.resize(limit); C.resize(limit);
    for (int i = n + 1; i < limit; i++) A[i] = 0;
    for (int i = m + 1; i < limit; i++) B[i] = 0;
    
    NTT(A, 1), NTT(B, 1);


    for (int i = 0; i < limit; i++)
        C[i] = A[i] * B[i] % MOD;
    NTT(C, -1);
    ll inv = qpow(limit, MOD - 2);
    for (int i = 0; i < limit; i++)
        C[i] = C[i] * inv % MOD;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

# 牛顿迭代

给定多项式 g(x)g(x)g(x),求满足 g(f(x))=0(modxn)g(f(x))=0\pmod{x^n}g(f(x))=0 (modxn) 的形式幂级数 f(x)f(x)f(x)

当 n=1n=1n=1 时,[x0]g(f(x))=0[x^0]g(f(x))=0[x0]g(f(x))=0 可以求出

假设现在已经得到了 (modx⌈n2⌉)\pmod{x^{\lceil \frac{n}{2}\rceil}} (modx⌈2n​⌉) 的解 f0(x)f_0(x)f0​(x)

有递归式:

f(x)≡f0(x)−g(f0(x))g′(f0(x))(modxn) f(x)\equiv f_0(x)-\frac{g(f_0(x))}{g'(f_0(x))}\pmod{x^n} f(x)≡f0​(x)−g′(f0​(x))g(f0​(x))​ (modxn)

# 多项式求逆

给定函数 h(x)h(x)h(x),有方程

g(f(x))=1f(x)−h(x)≡0(modxn) g(f(x))=\frac{1}{f(x)}-h(x)\equiv0\pmod{x^n} g(f(x))=f(x)1​−h(x)≡0 (modxn)

应用牛顿迭代可得:

f(x)≡f9(x)−1f0(x)−h(x)−1f02(x)≡2f0(x)−f02(x)h(x) \begin{aligned} f(x)& \equiv f_9(x)-\frac{\frac{1}{f_0(x)}-h(x)}{-\frac{1}{f_0^2(x)}}\\ &\equiv 2f_0(x)-f_0^2(x)h(x) \end{aligned} f(x)​≡f9​(x)−−f02​(x)1​f0​(x)1​−h(x)​≡2f0​(x)−f02​(x)h(x)​

于是,我们就得到了 f(x)f(x)f(x) 的递推是

根据主定理,时间复杂度为 O(nlog⁡n)O(n\log n)O(nlogn)

# 多项式开方

设给定函数为 h(x)h(x)h(x) 有方程:

g(f(x))=f2(x)−h(x)≡0(modxn) g(f(x))=f^2(x)-h(x)\equiv 0\pmod{x^n} g(f(x))=f2(x)−h(x)≡0 (modxn)

应用牛顿迭代可得:

f(x)≡f0−f02(x)−h(x)2f0(x)(modxn)≡f02(x)+h(x)2f0(x)(modxn) \begin{aligned} f(x)&\equiv f_0-\frac{f^2_0(x)-h(x)}{2f_0(x)}\pmod{x^n}\\ &\equiv \frac{f_0^2(x)+h(x)}{2f_0(x)}\pmod{x^n} \end{aligned} f(x)​≡f0​−2f0​(x)f02​(x)−h(x)​ (modxn)≡2f0​(x)f02​(x)+h(x)​ (modxn)​

时间复杂度 O(nlog⁡n)O(n\log n)O(nlogn)

# 多项式 exp

给定函数 h(x)h(x)h(x),有方程:

g(f(x))=ln⁡f(x)−h(x)(modxn) g(f(x))=\ln f(x)-h(x)\pmod{x^n} g(f(x))=lnf(x)−h(x) (modxn)

应用牛顿迭代可得:

f(x)≡f0(x)−ln⁡f0(x)−h(x)1f0(x)(modxn)≡f0(x)(1−ln⁡f0(x)+h(x))(modxn) \begin{aligned} f(x)&\equiv f_0(x)-\frac{\ln f_0(x)-h(x)}{\frac{1}{f_0(x)}}\pmod{x^n}\\ &\equiv f_0(x)(1-\ln f_0(x)+h(x))\pmod{x^n} \end{aligned} f(x)​≡f0​(x)−f0​(x)1​lnf0​(x)−h(x)​ (modxn)≡f0​(x)(1−lnf0​(x)+h(x)) (modxn)​

时间复杂度为 O(nlog⁡n)O(n\log n)O(nlogn)

# 拉格朗日差值

nnn 个点值 (xi,yi),(1≤i≤n)(x_i,y_i),\ (1\le i \le n)(xi​,yi​), (1≤i≤n),满足 xi≠xj,(i≠j)x_i\ne x_j,\ (i\ne j)xi​​=xj​, (i​=j),它们唯一确定一个 n−1n-1n−1 次多项式 f(x)f(x)f(x)

f(x)=∑i=1nyi∏j≠ix−xjxi−xj f(x)=\sum_{i=1}^n y_i\prod_{j\ne i}\frac{x-x_j}{x_i-x_j} f(x)=i=1∑n​yi​j​=i∏​xi​−xj​x−xj​​

拉格朗日差值定理用于点值表示转化成多项式形式,我们需要构造出一个多项式,满足 f(xi)=yif(x_i)=y_if(xi​)=yi​

首先,把 f(x)f(x)f(x) 拆成 nnn 个函数相加的形式 f(x)=f1(x)+f2(x)+⋯+fn(x)f(x)=f_1(x)+f_2(x)+\cdots+f_n(x)f(x)=f1​(x)+f2​(x)+⋯+fn​(x)

特别的,我们可以令 fi(x)f_i(x)fi​(x) 当且仅当在 x=xix=x_ix=xi​ 时 f(xi)=yif(x_i)=y_if(xi​)=yi​,其他时候都为 000

那么很显然可以构造出 fi(x)=A∏i≠j(x−xj)f_i(x)=A\prod_{i\ne j}(x-x_j)fi​(x)=A∏i​=j​(x−xj​),其中 AAA 是一个系数,我们把 fi(xi)=yif_i(x_i)=y_ifi​(xi​)=yi​ 带入

fi(xi)=A∏i≠j(xi−xj)=yi⟺A=yi∏i≠j(xi−xj) \begin{aligned} &f_i(x_i)=A\prod_{i\ne j}(x_i-x_j)=y_i\\ \Longleftrightarrow &\ A=\frac{y_i}{\prod\limits_{i\ne j}(x_i-x_j)} \end{aligned} ⟺​fi​(xi​)=Ai​=j∏​(xi​−xj​)=yi​ A=i​=j∏​(xi​−xj​)yi​​​

回代:

fi(x)=yi∏i≠j(x−xj)∏i≠j(x−xj)=yi∏i≠jx−xjxi−xj f_i(x)=\frac{y_i}{\prod\limits_{i\ne j}(x-x_j)}\prod_{i\ne j}(x-x_j)=y_i\prod_{i\ne j}\frac{x-x_j}{x_i-x_j} fi​(x)=i​=j∏​(x−xj​)yi​​i​=j∏​(x−xj​)=yi​i​=j∏​xi​−xj​x−xj​​

则:

f(x)=∑i=1nfi(x)=∑i=1nyi∏j≠ix−xjxi−xj f(x)=\sum_{i=1}^nf_i(x)=\sum_{i=1}^n y_i\prod_{j\ne i}\frac{x-x_j}{x_i-x_j} f(x)=i=1∑n​fi​(x)=i=1∑n​yi​j​=i∏​xi​−xj​x−xj​​

考虑计算

  • 特殊情况一:

只需要求一个 f(x0)f(x_0)f(x0​),那么暴力 O(n2)O(n^2)O(n2) 算即可

  • 特殊情况二:

只需要求一个 f(xo)f(x_o)f(xo​),并且满足 xi=ix_i=ixi​=i,是可以优化到 O(n)O(n)O(n) 的

上次更新: 2025/04/08, 18:03:31
数论
线性代数

← 数论 线性代数→

最近更新
01
Java基础语法
05-26
02
开发环境配置
05-26
03
pink 老师 JavaScript 学习笔记
05-26
更多文章>
Theme by Vdoing | Copyright © 2024-2025 Martian148 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式