多项式的计算(下)

本文约 12700 字。

Key Words:拉格朗日反演,转置原理,简易多项式复合,下降幂多项式,Chirp Z-Transform,Bluestein 算法,点值变换,位运算卷积,子集卷积,集合幂级数,高维幂级数

Todo:多元拉格朗日反演

转置原理

前文已经介绍过线性算法的概念,本节考虑线性算法的转置,并阐明一对互为转置的算法之间有何关系。

  • 线性算法的转置

    对于两个线性算法 ,记他们的转移矩阵为 ,若 ,则称 互为转置。

  • 初等矩阵

    以下三种矩阵称为初等矩阵:

    • 将单位矩阵 的第 行交换的矩阵。该矩阵左乘一个向量的效果为,将该向量的第 位交换。
    • 改为 的矩阵。该矩阵左乘一个向量的效果为,将该向量的第 位乘以
    • 改为 的矩阵。该矩阵左乘一个向量的效果为,将该向量的第 位加上第 位的 倍。

    容易发现,初等矩阵的转置仍然是初等矩阵。具体地:

    • 将向量的第 位交换:转置后不变。

    • 将向量的第 位乘以 :转置后不变。

    • 将向量的第 位加上第 位的 倍:转置后,将向量的第 位加上第 位的 倍。

  • 转置定理 转置定理给出了互为转置的两个线性算法之间的转化方法。


接下来,考虑如何由线性算法 得到线性算法

对于矩阵 ,它可以表示为若干初等矩阵的乘积: 每个初等矩阵对应一次“交换”,“乘加”等操作。在对某个向量执行线性算法时,只需将表示中的初等矩阵逐个左乘上去。

根据转置定理,有 根据 的初等矩阵表示可以得到 的初等矩阵表示。倒序逐乘初等矩阵的转置即可以同样的时间复杂度完成转置算法。

能互相转化,这给我们一个启发:如果计算 是困难的,可以先尝试计算 ,成功后,将整个算法转置,就能得到计算 的算法。这就是转置原理的基本思想。

贡献图

可以认为,线性算法维护一个含 个变量的数组,输入初状态,对其不断进行三种基本操作,最终输出末状态。然而实际情况中,算法的变量结构可能很复杂,且有中间变量,难以用线性代数的语言书写。我们需要更合适的刻画工具,为此,引入“贡献图”的概念。

将所有“修改”视为新建。即:修改某个变量时,为它创建一个新的“版本”,同时保留旧版本不删除。下图展示了一个例子: 这会使得所有操作都变为操作三。

建立一张有向图 ,对于操作“变量 加上变量 倍” ,连边 ,这样会形成一张有向无环图,因为老变量会贡献到新变量,而新变量不可能贡献到老变量。我们称 为线性算法的“贡献图”,以下是一个例子,省略了边上的乘数:

image-20250325145230509

图中的每条边代表一个操作,我们没有说明操作的计算顺序,但可以推断出:计算顺序一定是拓扑序。

如何对 进行转置?首先将操作顺序翻转,然后根据第三类初等矩阵的转置规则,将每条边的起点和终点交换,不难发现, 对应的贡献图是原来的反图:

有了贡献图,分析转置算法时就方便多了。

DFT 的转置*

仅用于常数优化

DFT 和 IDFT 的转移矩阵是对称的,故它们的转置是其自身。即 尝试将 DFT 的分治算法转置,这样可以得到一种新的计算 DFT 的方法。

原版 DFT 要先 bitrev(将序列编号二进制取反)再计算,转置后的 则先计算再 bitrev。注意到原版 IDFT 需要先 bitrev,两个紧接着的 bitrev 抵消,可以省略。这样可以减小 FFT 的常数。

下面介绍将 DFT 的分治算法转置的具体方法。分治计算时,最小操作单元具有如下形式(见“单位根复用”) 其中 为某常数, 是下一分治层的值。该操作转置后变为 根据转置定理,将所有最小操作单元转置,然后倒序执行即可。同一个分治层内部的最小单元互不干扰,只需将分治层倒序。

加法卷积的转置

数列 进行加法卷积得到 ,其中 若将 看成输入, 看成常量(主导线性算法的转移矩阵),记“卷”为线性算法 ,则该算法的转移矩阵为

考虑其转置算法 ,记 ,则 即为差卷积。

接下来用 表示转置后的多项式乘法。(符号右边的多项式视为转移系数,左边的多项式视为输入)

多点求值

  • 给出 次多项式 和常数 ,对 求各个

,将 视为转移系数,记线性算法 对应的矩阵 ,则

考虑其转置算法 ,记 ,有

构造成多项式: 这是分式求和问题,可以分治 FFT 计算,复杂度 。具体流程如下:

  • 对于分治区间 ,维护分母 与分子

  • 填写到叶节点

  • 自底向上分治,处理 时,记

  • 最终,计算 即可得到答案。

将该线性算法 转置,就得到多点求值算法 。具体流程如下:

  • 与输入()无关,只和算法的转移矩阵有关,为常量,先用分治 FFT 预处理。

  • 输入 ,计算

  • 自顶向下分治,对于区间 的贡献图为 将其转置, 的贡献图为

  • 最终得到的各个 即为答案。

值得留意的是,由于顺序颠倒,在 中,作为输入的 一开始被放置在 处,答案由 给出; 则倒过来了,输入 被安放在 处,答案由 给出。

复杂度 ,相较于传统的分治取模算法,较易实现且常数更小。



拉格朗日反演

基本概念

  • 形式幂级数的复合逆

    对于形式幂级数 ,若 ,且 ,则称 的复合逆。记为

  • 复合逆的性质

    • 复合逆是对称的,即 当且仅当
    • 形式幂级数 满足 ,则它拥有唯一的复合逆。

证明:

性质一:令

易知要么 要么 。由

性质二:设 的复合逆为 ,易知 ,对于 其中 ,可以解出 。这个递推可以确定唯一的

  • 形式洛朗级数

    引入负次数, 称作形式洛朗级数,其中 为有限值。

引入有限的负次数后,幂级数的乘法(数列的加法卷积)仍然容易定义。

原先 的幂级数无乘法逆,若考虑形式洛朗级数,则一切幂级数(除了 )都存在乘法逆。具体地,记 的最低项为 ,则 有常数项,其乘法逆有定义,故

注:若涉及到负无穷多次项,某些收敛的性质可能失效。

如尝试将 写成封闭形式,若缩写为 ,再展开成 ,显然错误。

一元拉格朗日反演

拉格朗日反演指明了提取复合逆的一项系数的方法,这是为数不多的能从封闭形式中提取系数的方法之一。

  • 引理(形式留数)

    对于无常数项,有一次项的整式 ,有

证明:当 ,而求导不可能产生 项。

此处构造 ,使常数项非零,便于考虑。


  • 引理

    对于无常数项,有一次项的形式幂级数 和任意洛朗级数 ,有

证明:,根据引理


  • 拉格朗日反演

    形式幂级数 无常数项,有一次项,则

    (扩展) 为形式洛朗级数,有

证明:

即可得到经典情况。


  • 另类拉格朗日反演

    形式幂级数 无常数项,有一次项,则 (扩展) 为形式洛朗级数,有

证明:

即可得到经典情况。

对于另类拉格朗日反演,分歧在于得到 的方式:构造时不求导,而直接将 乘上去。


两者比较,拉格朗日反演的形式简单,便于推导;另类拉格朗日反演证明思路直接,且能处理 的情况。

实际计算时,可以将定理改写成 其中 有常数项,可以求逆。整个计算过程在形式幂级数中完成,无需涉及形式洛朗级数。


  • 例题 6.1.5. 幂的横截

    已知 互为复合逆,给出 。对 分别求出

Solution:记 ,目标是 ,使用扩展拉格朗日反演

只需计算 的各项系数,复杂度

进一步地,若 没有复合逆,可能有以下两种情况:

情况一, 的最低次项次数 ,记 ,那么 就有复合逆。 只在 时有值,故对 计算幂的横截即可。

情况二,,记 ,转化为正常情况或情况一。对 计算幂的横截,最后 ,二项式定理展开后可以卷积。



多项式复合

简易多项式复合

  • 右复合

    给出 次多项式 ,计算 的各项系数。

提取系数得

,则

差卷积计算即可,复杂度


  • 右复合

    给出 次多项式 ,计算

配方得


  • 右复合

    给出 次多项式 ,计算 的前 项系数。

根据 ,有 。只需计算 与一次乘法。

复合 的情形类似。


  • 右复合


此外,我们可以在 的时间内右复合任意二次分式 或任意三次式 ,思路都是将要复合的式子拆成一系列 和一次分式 的复合。这样的手段对五次及以上的一般多项式无效(五次以上方程无根式解)。而且,随着次数增大,时间常数也随之增大,在实践上不如下面的 通解。

参考:


  • 右复合 短有理分式

    给出多项式 以及短多项式 (长度为常数),求 的前 项。

先解决短有理整式,即求

可以分治 FFT 解决,对于分治区间 ,记 ,有分治转移 复杂度

若加入分母 ,分别维护分子分母,最后求逆即可。


  • 右复合 (其中右复合 G 容易计算)

    给出多项式 ,求 的前 项。

的系数按下标模分类,记 代入 对每个 分别计算。需要计算 次右复合 以及多项式乘法。


  • 右复合

    给出多项式 ,计算 的前 项系数。

只需要对每个 求出 (甩掉阶乘),记 ,则

分治 FFT 即可。复杂度


Bostan–Mori 算法

它的一个更初步的应用是求线性递推的远处项,推荐先学习《线性递推》一节。

Bostan–Mori 算法可用于提取二元分式的一行

上下同乘 ,注意到 ,故 只有 的偶次幂有系数,可以表示为 。记 ,将 的系数奇偶分类,表示成 ,得 分母只有偶系数,分子奇偶系数分离,讨论 的奇偶性,当 为偶数时只涉及 ,为奇数时只涉及 ,故 每次递归,需要保留的 的次数减半, 的次数加倍,规模近似不变。

递归层数为 ,复杂度 。其中 为初始的 的次数,当 为常数时,复杂度

多项式复合

给出多项式 ,求 将其视为线性算法, 视为输入, 视为贡献系数。考虑该线性算法的转置 构造成多项式 其中

Bostan–Mori 算法可 计算 。将该算法转置,就解决了多项式复合。

多项式复合逆

给出 的前 项,,求 的前 项。

【例题6.1.5】利用复合逆解决了“幂的横截”,结论是 换言之,若求出各个 ,就能得到 的各项系数,计算 次方即得

这将目标转化为“幂的横截”,记 ,将其构造为多项式 可用 Bostan–Mori 算法 计算。(这为“幂的横截”提供了通解)


一元多项式的其他常见算法

牛顿级数与下降幂多项式

  • 多项式序列 满足 次首一多项式。称这样的一组多项式为基。

例如 就是一组基,称为方幂基。

  • 基表示

    对于任意多项式 和任意基 ,记 的次数为 ,总能找到一个系数序列 使得 这种表示 的方法称作在基 上的表示。

证明:找出 的最高次 ,令 ,然后令 ,这样能使得最高次项变为 。不断重复这一过程即可得到数列


我们不仅可以用方幂 ,还可以用其他的基来表示多项式,下面是两种常见的扩展:

  • 牛顿级数

    形如 的多项式称为牛顿级数。

  • 下降幂多项式

    形如 的多项式称为下降幂多项式。

对牛顿级数 使用二项式反演可得 二项式反演可以卷积加速,我们可以在 的时间内在系数 与点值 之间相互转换。

若要计算两个牛顿级数的乘法,可以先转换为点值,让点值相乘,再转换为系数。

对于下降幂多项式,由于 ,两者的系数容易转换。

与普通多项式相转化时,需要快速插值或求值,复杂度


  • 例题 6.1.7. 拉格朗日插值2

    给定一个不超过 次的多项式 个点值 ,和一个正整数 ,求

    答案对 取模,

Solution:首先将 的点值转化为下降幂多项式 ,再利用下降幂的二项式定理,计算 的各项系数(与上文“复合 ”方法相同),最后转化回点值


Chirp Z-Transform

给出 次多项式 和常数 ,对 求出

  • 引理:

利用该引理,可以构造卷积:

,则 可以差卷积计算,复杂度

注:各个 可以两次前缀积计算,避免快速幂,以减小常数。


任意长度 DFT/IDFT:Bluestein 算法

  • 循环卷积

    两个数组 的长度为 的循环卷积是一个新的数组 ,其中

循环卷积等价于 下的多项式乘法。

  • 定理

    长度为 的 FFT 在计算长度为 的循环卷积。

证明:

FFT 计算的是 ,其中点表示点乘。展开得

应用单位根反演

即为循环卷积。或对循环卷积定义式进行单位根反演,可以从另一个方向验证。

我们用 FFT 计算多项式乘法时,会“选择足够多的点值”,多于两多项式的次数之和。虽是循环卷积,由于卷积数组够长,实际上没有溢出,和加法卷积等效。

前文的 FFT 算法只能处理长度 的情形(稍加改造可以计算 质因子不大的情况)。如何计算 为任意值的循环卷积?一个朴素的想法是,先计算双倍长度的普通加法卷积,然后再把循环的部分手动添加。这做法的确可行,但没有保留“点值”的性质。我们希望实现任意长度的 DFT/IDFT,而不仅仅是卷积。

注意到 DFT 相当于对 做 Chirp Z-Transform,于是可以 求任意长度 DFT(IDFT 可以由 DFT 得到)。这被称作 Bluestein 算法。


位运算卷积与集合幂级数

点值变换的构想

前文对任意二元运算 定义了“ 卷积”,记其符号为 。我们尝试推广“求值-插值法”的思想,定义 卷积的点值变换(Point value Transform)

  • 点值变换

    二元运算 定义域、值域均为

    若存在线性变换 ,使得对于任意数组

    (其中点表示点积)则称 卷积对应的点值变换。

点值变换将卷积转化为点积。注意到点乘具有交换律、结合律,若 卷积有点值变换,那么 运算必须要有交换律、结合律。

加法卷积并不满足这里说的“定义域、值域均为 ”,但 FFT 计算的其实是长度为 的循环卷积,其中下标的运算 符合定义。


如何设计我们想要的线性变换?设 的变换系数,展开

又根据 ,将左侧的 代换掉

对比系数,再由序列 的任意性,可知

我们需要构造矩阵 满足这一条件。而且,为了从点值变回系数,我们还需要 的逆变换 ,这要求矩阵 有逆。

例如,对于长度为 的循环卷积,我们知道 DFT 的系数 ,那么

符合公式。

位运算卷积

先约定一些必要的记号。

  • 位表示

    记位的大小为 (其中 ),将自然数 拆成 的形式,其中 ,则称 的位表示。

  • 位运算

    有一系列二元运算 ,其中 定义域和值域为 。自然数 的位表示为 ,计算 ,位表示 对应的数为 ,则称 通过位运算得到 。这种位运算可以记作二元运算

定义为了一般性稍显冗杂。实际应用中,多数情况有 (即 进制数),且每个位的运算 规则相同。

例:按位与()、按位或()、按位异或()的位大小均为 ,位内运算 值域均为 。三者的位内运算的取值表为

位运算卷积的点值变换

对于一个(值域有限的)位运算 ,如果我们已经知道其各个位内运算 对应的点值变换系数 (称作位矩阵),则有如下方法构造 卷积的点值变换。

的位表示为 ,构造

由于位运算直接各个位之间互不干扰,易知 符合公式

为了从点值变回系数,我们还需要

  • 定理

证明:证法和“多元反演”一致。


已知位运算 的位矩阵,有如下计算 的算法:

记最高位为第 位,位值域为 ,将 按下标最高位分成连续等长的 ,每段抹去最高位独立进行 变换,记结果为 ,则 这实际上是由序列构成的向量 左乘 得到 。暴力计算的复杂度是 ,如果乘矩阵 有快速算法,亦可采用之。

考虑计算的复杂度,在位运算卷积中 ,记总位数为 ,复杂度递推式为 ,得复杂度

计算 的方法相同,用 作为系数即可。

经典位运算卷积

记位矩阵为 ,三种经典位运算卷积的构造如下。

  • or 卷积

扩张成完整的变换系数 ,可以发现 恰是高维前缀和,相应地, 恰是高维前缀差分。


  • and 卷积

扩张成完整的变换系数 ,可以发现 恰是高维后缀和,相应地, 恰是高维后缀差分。


  • xor 卷积

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
const int
mod = _____,
inv2 = _____,
Wor[2][2] = {{1,0}, {1,1}},
Wand[2][2] = {{1,1}, {0,1}},
Wxor[2][2] = {{1,1}, {1,mod-1}},
IWor[2][2] = {{1,0}, {mod-1,1}},
IWand[2][2] = {{1,mod-1}, {0,1}},
IWxor[2][2] = {{inv2,inv2}, {inv2,mod-inv2}};
// 三种点值变换的系数矩阵,以及它们的逆矩阵
void FPT(int *A, int n, const int W[2][2]) {
//根据位矩阵 W 快速计算点值变换
for (int len=1; len<n; len<<=1) // 枚举子问题的长度
for (int p=0; p<n; p+=2*len) // 枚举本问题的左侧起始位置
for (int i=p; i<p+len; i++) {
int sav0 = A[i];
A[i] = (W[0][0]*A[i] + W[0][1]*A[i+len]) %mod;
A[i+len] = (W[1][0]*sav0 + W[1][1]*A[i+len]) %mod;
}
}
void bitmul(int *A, int *B, int *C, int n,
const int W[2][2], const int IW[2][2]) {
// 根据位矩阵 W, IW 计算 A 和 B 的位运算卷积。
FPT(A, n, W);
FPT(B, n, W);
for (int i=0; i<n; i++)
C[i] = A[i]*B[i] %mod;
FPT(C, n, IW);
}

计算 or 卷积、and 卷积的点值变换的算法称作快速莫比乌斯变换(FMT),计算 xor 卷积的点值变换的算法称作快速沃尔什变换(FWT)。


扩展位运算卷积

将位运算卷积扩展到位大小 的情况。

  • 高维 max 卷积(将按位或扩展为每一位取 max)

构造 为在第 位上做前缀和, 为前缀差分。

  • 高维 min(将按位与扩展为每一位取 min)

构造 为在第 位上做后缀和, 为后缀差分。

  • 不进位加法卷积(将按位异或扩展为每一位相加模

在每个位内是循环卷积,若单位根存在,根据 DFT/IDFT,有



子集卷积

位二进制数视为大小为 的集合,其中 表示出现, 表示不出现。集合的并相当于取 and,集合的交相当于取 or,集合大小 的二进制表示中 的个数。

  • 子集卷积

    定义序列 的子集卷积为 ,其中

这和前文定义的“ 卷积”不太一样, 卷积中每个乘积 都有贡献,而此处只有 的乘积才有贡献。即只考虑集合的不交并,相交则不贡献。

有多少对有贡献的 ?答案是 ,和“枚举子集”的复杂度相同。这说明子集卷积可以暴力 计算。

考虑使用卷积知识加速计算。直接套用前面学习的或卷积只能求 ,无法再满足

注意到 等价于 。而 可以用加法卷积来描述。人为增加一个元 ,将 替换为 ,计算或卷积。提取 即为满足 的乘积的贡献。

就得到答案。暴力计算关于 的多项式乘法,复杂度 。关于 的多项式称为“占位多项式”。

(子集顺序的)全在线子集卷积

  • 的子集卷积。在你正确地对于所有 计算出 后才能得到 的值。计算

按照 的顺序计算 ,这样就能保证需要的值已经得到。枚举子集可以做到

相当于按照 的次数从小到大计算,将 视为主元,对 逐次计算 。需要计算 次或卷积,利用 PT 变换的线性性,只需 次变换。复杂度仍然是



集合幂级数

  • 集合幂级数

    定义 由这样的 构成的形式幂级数称为集合幂级数。

位数为 的集合幂级数也可以定义成有 个元 的多元形式幂级数,每个元 取模,这样次数只能是 ,相乘也符合规则。

集合幂级数的单位元为 (或写作 ),可视为“常数项”。

容易定义集合幂级数的乘法逆、有理次幂。此外,仍可用无穷求和定义指数和对数: 两者都要求

与经典形式幂级数不同的是,集合幂级数有“点值”,也就是点值变换后得到的占位多项式。这为计算带来了很大便利,比如说,若要计算乘法逆,只需将点值占位多项式取倒数,再变换回去。 也类似。由于占位多项式一般较短,此处常用 的递推法。


多元多项式

二元多项式乘法

  • 给出二元多项式 的最大次数分别为 ,计算两者的乘积

二元多项式乘法对应二元加法卷积:

考虑如何计算。将 扩大两倍,转化为计算二元循环卷积,这相当于只有两个“位”的位运算卷积。可以发现,先每列做 DFT,再每行做 DFT,就能得到“点值”;点乘后,先每行做 IDFT,再每列做 IDFT,即可恢复为系数。

复杂度

多元多项式乘法

  • 我们有两个多元多项式 ,希望计算

    ,希望得到 的算法。

在高维加法卷积中,由于每一维度上次数都会翻倍,所以实际计算系数总量是 级别的。当 较大时,复杂度不尽如人意。

下面给出一个 计算 元多项式乘法(的截断)的方法。由 一般至少为


将一组下标 看做位表示(位值域为 ),可以将它们编码为一个自然数,即令

这样就把多维映射到了一维上。

此时,下标 的加法对应着大数 的加法,但要将超出截断范围(产生进位)的贡献去除。

模仿子集卷积,考虑设置一个合适的占位多项式来辅助判定进位,将错误的贡献分流除去。构造占位函数 ,满足:

  • 不进位,则
  • 进位,则

这样,我们计算二元多项式 的乘法,然后利用第二维去除无用贡献即可。具体地,在 项只保留 系数。

剩下的问题就是找到一个合适的 函数。模仿子集卷积,不难想到 (各位数码之和),但这个函数的值域太大,会导致 的次数很高,不便计算。

,注意到 在第 位进位当且仅当 可以想到令 这样,虽然单个 的值仍然很大,但由于 可知 。只需在 上记录长度为 的循环卷积即可得到所有信息。

在实现时,我们需要计算 的乘法。我们将 设为主元进行 FFT,复杂度是 。得到的“点值”是 的多项式,暴力计算乘法,一次乘法复杂度 ,点积总复杂度

多元多项式的求导与牛顿迭代

我们已经把多元多项式乘法转化为二元多项式 的乘法,具体地,每次相乘后在 系数中保留 项。

观察那些被去除的贡献,由于产生了进位,他们分布于比 更低的项,在接下来的运算中,这些贡献没有机会回到 项。由此可见,我们的乘法相当于只维护二元多项式在 上的上轮廓。

我们考虑完整的二元多项式(即每次乘法后不进行去除),以 为主元,可以正常定义其求导和牛顿迭代。牛顿迭代中的运算全部转化为乘法,若只关心上轮廓,可以在计算过程中只保留上轮廓。将 的计算封装后,具体实现和一元的情形非常相近。