从多项式入门到形式幂级数

好好好。
开了个大坑。
我估计写一半就发布了。如果没了下文属于正常(

目前的前置知识:加减乘除,幂运算,未知数

多项式

单项式是这个:\(kx^n\)

多项式就是多个单项式相加,一般表示为:\(F(x) = a_0+a_1x+a_2x^2+...+a_nx^n\)
可以用求和符号简写成

\[F(x) = \sum_{i=0}^n a_ix^i \]

其中称 \(a_0\) 为常数项,\(a_ix^i\)\(i\) 次项,多项式的次数就是最高次项的次数 \(n\)

(求和符号 \(\sum_{i=a}^{b}\) 代表从 \(i\)\(a\)\(b\) 遍历每一个数然后求和)

一般用大写字母表示多项式。当然我可能有时忘了(

之后会遇到无限次多项式:\(F(x) = a_0+a_1x+a_2x^2+...\)

\[F(x) = \sum_{i=0}^{+\infty} a_ix^i \]

不过不要惊慌,无非就是项数多了点。

多项式简单运算

多项式加法:\(H(x) = F(x)+G(x)\)

\[(f_0+f_1x+...+f_nx^n)+(g_0+g_1x+...+g_nx^n)=(f_0+g_0)+(f_1+g_1)x+...+(f_n+g_n)x^n \]

\[\sum_{i=0}^{n}f_ix^i+\sum_{i=0}^{n}g_ix^i=\sum_{i=0}^{n}(f_i+g_i)x^i \]

所以有 \(h_i= f_i + g_i\)

多项式减法:\(H(x) = F(x)-G(x)\)

\[(f_0+f_1x+...+f_nx^n)-(g_0+g_1x+...+g_nx^n)=(f_0-g_0)+(f_1-g_1)x+...+(f_n-g_n)x^n \]

\[\sum_{i=0}^{n}f_ix^i-\sum_{i=0}^{n}g_ix^i=\sum_{i=0}^{n}(f_i-g_i)x^i \]

\(h_i= f_i - g_i\)

一般减法为加法的逆运算,在有减法逆元(你可以理解为负数)的情况下,减法就是加负数。

多项式乘法:\(H(x) = F(x)\times G(x)\)(简写为 \(H(x) = F(x)G(x)\)

用乘法分配律拆一下式子

\[(f_0+f_1x+...+f_nx^n)(g_0+g_1x+...+g_nx^n)=(f_0g_0)+(f_1g_0+f_0g_1)x+...+(f_ng_0+f_{n-1}g_1+...+f_0g_n)x^n \]

由于 \(f_ix^i \times g_jx^j = f_ig_jx^{i+j}\),所以 \(F\)\(i\) 项系数 \(f_i\)\(G\)\(j\) 项系数 \(g_i\) 会加到 \(H\) 的第 \(i+j\)\(h_{i+j}\) 上面。
从而 \(h+i = f_ig_0+f_{i-1}g_1+...+f_1g_{i-1} + f_0g_i\),即

\[(\sum_{i=0}^{n}f_ix^i)(\sum_{i=0}^{n}g_ix^i)=\sum_{i=0}^{n}\Big(\sum_{j=0}^{i}f_jg_{i-j}\Big)x^i \]

\(h_i= \sum_{j=0}^{i}f_jg_{i-j}\)

请尽快理解求和符号(如果你不懂。

多项式的乘法,一般称作卷积。

多项式除法还不好定义。我们之后再讲。

所以多项式有什么用?

讲这么点,你可能不会问多项式有什么用。
但我还是讲一下吧(

首先不排除某些题就直接让你算多项式的情况(

其次多项式乘法的性质,及 \(f_ig_j \to h_{i+j}\),符合一些问题的计算,例如背包问题。

我们用 \(f_i\) 代表选择物品大小恰为 \(i\) 时的方案数,那么我们可以尝试计算这样一个多项式:第 \(i\) 项系数恰好为 \(f_i\)(即生成函数)。我们在计算后再取出系数,就可以得到答案。

我们考虑每物品选择是否选择,若选择,则会让物品大小增加 \(k\),此时 \(f_{i}\) 会贡献至 \(f_{i+k}\) 上,若不选择,则 \(f_{i}\) 贡献至他自己。

我们可以通过多项式表示这个过程,每次多一个物品,相当于乘上 \(1+x^k\) 这个多项式。之后我们要算的就是多个多项式相乘。

多项式乘法复杂度可以优化,所以可以通过将问题表示成多项式来简化问题,或者优化复杂度。

快速傅里叶变换 FFT

上面刚说完,现在讲讲多项式乘法怎么优化复杂度。但这很复杂,需要从虚数开始讲起,懂得可以自觉跳过。

虚数

前置知识:实数

定义虚数 \(i\),满足 \(i^2= -1\)
所以有 \(i = \sqrt{-1}\)。众所周知,\(\sqrt{-1}\) 不在实数范围内,所以叫他虚数。

复数定义为实数+虚数,一般记为 \(z\)

\[z=a+bi \]

其中 \(a,b\) 都为实数,\(a\) 为实部,\(bi\) 为虚部。

我们暂且记 \(a+bi\)\((a,b)\)

C++里面是有复数的STL的,但建议还是手写(

复数运算

加法:\((a,b) + (c,d) = (a+c,b+d)\)
减法:\((a,b) - (c,d) = (a-c,b-d)\)
乘法:\((a,b) + (c,d) = (ac-bd,ad+bc)\)
乘法比较有趣,具体来说是这样:

\[(a+bi)(c+di)=ac+adi+bidi+bic=ac+adi-bd+bci= (ac-bd)+(ad+bc)i \]

除法可以通过乘上逆元来实现,逆元 \(z^-1\) 满足 \(z\times z^-1 = 1\)
这里讲如何计算一个复数的逆元:

\[\frac{1}{a+bi}=\frac{a-bi}{(a+bi)(a-bi)}=\frac{a-bi}{a^2+b^2}=\frac{a}{a^2+b^2}-\frac{b}{a^2+b^2}i \]

一般记成倒数第二个就行了。主要用到平方差公式。

复数除了 \(0\) 皆有逆元。

复平面

将复数 \(a+bi\) 表示成平面上的点 \((a, b)\)。实数就是 \(x\) 轴上的数。

复数加减法在复平面上类似于向量加减法。(向量或许之后用到会讲。

复数乘法比较神奇。
复数的模长记为 \(|z| = a^2 + b^2\)。即到原点的距离。
复数的幅角记为 \(\arg z\),即原点到其的射线与 \(x\) 轴夹角。
那么复数乘法满足:
\(|z_1z_2| = |z_1||z_2|\),模长相乘。
\(\arg z_1z_2 = \arg z_1 + \arg z_2\),幅角相加。

可以画图理解。这里就不证明了。

单位根

\(x^n=1\)\(n\) 个解都是 \(n\) 次单位根。即 \(n\) 次单位根有 \(n\) 个。
单位根在复平面单位圆上,\(n\) 次单位根为单位上从 \((1,0)\),开始的 \(n\) 个等分点。

记从 \((1, 0)\) 逆时针旋转下一个单位根为 \(w_n\)。也相当于就是相邻两个单位根之间的间隔。
则有从 \((1, 0)\) 逆时针旋转第 \(k\) 个单位根为 \(w_n^k\)。(你理解的可能差个 \(O(1)\) 的常数,反正差不多就这意思(

单位根具有如下性质:

  • \(w_n^n = 1\) 走一圈回来了。
  • \(w_n^k=w_{2n}^{2k}\) 相当于点的密度增加一倍,但是位置不变。
  • \(w_{2n}^{k+n}=-w_{2n}^{k}\) 走一半相当于实部和虚部同时取反。

多项式表示法

多项式可以表示成一开始的方式:\(F(x) = a_0+a_1x+a_2x^2+ \dots + a_nx^n\)

然后可以看做一个向量 \((a_0, a_1, \dots ,a_n)\)

这上面都是系数表示法,就是记录系数以记录一个多项式。

还有一种点值表示法。

通过记录 \(n\) 次多项式 \(n + 1\) 个位置的点值可以还原多项式。(一个基本方法是待定系数法)

也可以表示成一个点值向量 \((y_0, y_1, \dots ,y_n)\) 前提是规定所有 \(x_n\)

一般情况下,多使用系数表示法。

快速傅里叶变换

好的终于开始正题了。

如果我们直接暴力求系数表示法的多项式乘法,则复杂度为 \(\operatorname{O}(n^2)\)
需要枚举 \(f_i,g_j\) 并贡献到 \(h_{i+j}\)

但是当我们求点值表示法下的多项式乘法,则只需要将每个点值相乘。复杂度 \(\operatorname{O}(n)\)

FFT使用的便是这个原理。

通过 FFT \(\operatorname{O}(n\log n)\) 求出 \(f, g\) 的点值表示,然后 \(\operatorname{O}(n)\) 得到 \(h\) 的点值表示,再用 IFFT \(\operatorname{O}(n\log n)\) 反向计算出 \(h\) 的系数表示。

快速傅里叶变换 FFT

我们有一个多项式 \(F(n) = \sum_{i=0}^{n-1} f_i x^i\)(注意次数是 \(n-1\)),我们需要求出其在任意 \(n\) 个位置 \(x_0, \dots, x_{n-1}\)的点值。

FFT 取 \(x_i = w_n^i\),根据单位根 \(w_{2n}^{2k} = w_{n}^{k}\) 的性质,我们可以将多项式分为奇偶项。

为了方便,我们先将多项式通过在系数表示后面加 \(0\)\(n\) 扩充到 \(2\) 的整数幂。

\[F(x)=a_0+a_1x+a_2x^2+\dots+a_{n-1}x^{n-1} \]

我们把其分成奇偶项:

\[F0(x)=a_0+a_2x+\dots+a_{n-2}x^{\frac{n}{2}-1} \]

\[F1(x)=a_1+a_3x+\dots+a_{n-1}x^{\frac{n}{2}-1} \]

那么有

\[F(x)=F0(x^2)+xF1(x^2) \]

我们考虑求出 \(F0\)\(F1\) 在每一个 \(\frac{n}{2}\) 单位根的值后如何得到 \(F\) 在每一个 \(n\) 次单位根下的值。

\[F(w_n^i)=F0(w_n^{2i})+w_n^iF1(w_n^{2i}) \]

因为有 \(w_{2n}^{2k} = w_{n}^{k}\),所以可以得到:

\[F(w_n^i)=F0(w_{\frac{n}{2}}^i)+w_n^iF1(w_{\frac{n}{2}}^i) \]

那你发现这样就可以从 \(F0(w_{\frac{n}{2}}^i), F1(w_{\frac{n}{2}}^i)\) 直接得出 $$F(w_n^i)$$。

\(F0(w_{\frac{n}{2}}^i), F1(w_{\frac{n}{2}}^i)\) 是确定的。(当 \(\frac{n}{2} \leq i\) 时,\(w_{\frac{n}{2}}^i = w_{\frac{n}{2}}^{i - \frac{n}{2}}\)

实现方法多样,有很多优化空间,我这里先不讲了(

逆快速傅里叶变换 IFFT

我们有一个多项式 \(F(n) = \sum_{i=0}^{n-1} f_i x^i\),我们需要知道其在 \(x=w_n^i(0\leq i < n)\)\(n\) 个位置的值 \(y_i(0 \leq i < n)\)

我们要求出其每一项系数。

IFFT表示,我们将 \(y_i\) 作为 \(i\) 次项系数构造函数 \(G(x)\),那么 \(G(w_n^{-i})\) 就是 \(F(n)\)\(i\) 次项系数。

我们推一下式子:

\[y_i = \sum_{j=0}^{n-1} a_j(w_n^i)^j \]

\[G(w_n^{-k}) = \sum_{i=0}^{n-1} y_i(w_n^{-k})^i = \sum_{i=0}^{n-1}\sum_{j=0}^{n-1} a_j(w_n^i)^j(w_n^{-k})^i \]

\[G(w_n^{-k}) = \sum_{j=0}^{n-1} a_j\sum_{i=0}^{n-1}(w_n^{j-k})^i \]

\(j-k = 0\) 时,

\[\sum_{i=0}^{n-1}(w_n^{j-k})^i = \sum_{i=0}^{n-1}1^i = n \]

否则

\[\sum_{i=0}^{n-1}(w_n^{j-k})^i = \frac{1 - (w_n^{j-k})^n}{1 - w_n^{j-k}} = \frac{1 - (w_n^n)^{j-k}}{1 - w_n^{j-k}} = \frac{1 - 1}{1 - w_n^{j-k}} = 0 \]

所以 \(G(w_n^{-k}) = na_k\)

至此,快速傅里叶变换就讲完了,正变换和逆变换本质上是同一个东西。

快速数论变换 NTT

快速傅里叶变换有个缺点。
其需要用到复数单位根 \(w_n = \cos(\frac{2\pi}{n}) + \sin(\frac{2\pi}{n})i\)
而复数单位根不可避免的要涉及三角函数 \(\sin \cos\),会带来大量精度误差。(\(10^-6\) 左右好像)
而且过程中不可取模。

NTT便是取模意义下的 FFT,其使用数论中的原根替代单位根。因为原根具有和单位根相同的性质。

整数 \(a\)\(m\) 意义下的原根定义为最小的正整数 \(n\) 满足 \(a^n \equiv 1 \pmod p\),记为 \(\delta_m(a)\)

原根

使得 \(\delta_m(g)=\phi(m)\) 的整数 \(g\) 被称为模 \(m\) 意义下的原根,或 \(m\) 的原根。

原根可能不存在,也可能有多个。

(若一个数有原根,则原根个数为 \(\varphi(\varphi(m))\)
(\(m\) 有原根当且仅当 \(m=2,4,p^\alpha,2p^\alpha\),其中 \(p\) 为奇质数)

一个数 \(m\) 的最小原根为 \(\operatorname{O}(\log m)\)

NTT

一般选择模数为质数 \(p\),则原根 \(g\) 满足 \(g^{p-1} \equiv 1 \pmod p\)

由于要将单位圆均分成 \(n\) 份,需要让 \(n\) 能够整除 \(p-1\)。同时我们的 \(n\)\(2\) 的整数幂。

\(p = qn+1\),则需要一个足够大的 \(p\),满足 \(p = q2^k+1\)

满足这个条件的的质数,题目中一般选择 \(998244353 = 7 \times 17 \times 2^23 + 1\)\(3\) 为其原根。

接下的操作皆与 FFT 一致,只需要把 \(w_n\) 换成 \(g^\frac{p-1}{n}\) 并把所有操作带上模 \(p\) 即可。

一般题目若有取模则使用 NTT,若需求小数运算则只能用 FFT。

任意模数多项式乘法(MTT)

如果阴间出题人出了个模 \(998244853\) 的多项式题,我们如何对敌?

注意到模数没有原根,或者 \(p-1\) 无法被 \(2^k\) 整除。我们无法直接使用 NTT。

同时答案过大,我们无法直接使用 FFT。

多模数NTT

对于 NTT,我们只能用固定的几个模数去做。

所以我们考虑选择几个有原根的模数。然后使用扩展中国剩余定理,推出原系数时取模。(用中国剩余定理可能会炸 long long)

比如说 \(469762049, 998244353, 1004535809\),三个数的原根皆为 \(3\)。(可以不相同,但相同更方便)

拆系数FFT

也可以将多项式的系数 \(a_i\) 拆成 \(kb_i + c\),其中 \(k\) 是一个常数。

那么我们假设拆成这样:\(F(x) = kA(x) + B(x), G(x) = kC(x) + D(x)\)

于是有

\[F(x)G(x) = k^2A(x)C(x)+k(A(x)D(x) + B(x)C(x))+B(x)D(x) \]

\(4\) 次 FFT 和 \(4\) 次 IFFT 就可以了。

\(A(x)D(x) + B(x)C(x)\) 加在一起后同时 IFFT 可以节省一次 IFFT 次数。

多项式运算

现在我们来讲一下如何快速进行某些多项式的运算。

多项式求逆(多项式除法)

有一多项式 \(F(x) = \sum_{i=0}^{n-1} f_ix^i\),我们要求出其在模 \(x^n\) 意义下的逆 \(G(x)\)

即,\(F(x)G(x) \equiv 1 \pmod{x^n}\)

运用分治的思想。考虑先求出 \(G_0(x)\),使得 \(F(x)G_0(x) \equiv 1 \pmod{x^{\frac{n}{2}}}\)

容易发现其实 \(G_0(x)\) 就是 \(G(x)\) 的前 \(\frac{n}{2}\) 项,即:

\[G(x) - G_0(x) \equiv 0 \pmod{x^{\frac{n}{2}}} \]

两边以及模数同时平方。因为左侧在模数以下的项系数皆为 \(0\)

\[G(x)^2 - 2G(x)G_0(x) + G_0(x)^2 \equiv 0 \pmod{x^n} \]

我们就可以将模数变成 \(x^n\)。这时候两边同乘 \(F(x)\),得到:

\[F(x)G(x)^2 - 2F(x)G(x)G_0(x) + F(x)G_0(x)^2 \equiv 0 \pmod{x^n} \]

\[G(x) \equiv G_0(x) - 2F(x)G_0(x)^2 \pmod{x^n} \]

可以使用多项式乘法递归计算。复杂度:\(T(n) = T(\frac{n}{2}) +O(n\log n) = O(n\log n)\)

多项式求导

\[(x^a)'=ax^{(a-1)} \]

\[(f(x)+g(x))'=f'(x)+g'(x) \]

所以直接对每一项求导,可以 \(O(n)\) 算。

多项式积分

积分是求导的逆运算。

\[\int (x^a)' \mathrm{d} x=\frac{x^{(a+1)}}{a+1} \]

所以同样可以 \(O(n)\) 算。

多项式 ln

\[\ln f(x) = \int \frac{f'(x)}{f(x)} \mathrm{d} x \]

所以我们将求导求逆乘法积分直接算就行了。

posted on 2025-01-10 13:51  Evan_song  阅读(149)  评论(0)    收藏  举报