多项式简明百科全书

\(1\)、多项式乘法

利用\(FFT\)就可以将多项式乘法的复杂度优化到\(O(n\log n)\)。由于其讲解较为繁琐并且已逐渐普及(想必读者也不是来学这个的),因此略过\(FFT\)以及同样普及的\(NTT\)

至于\(MTT\),我们可以将系数拆成\(32768\cdot a+b\)的形式缩小值域,将一个多项式拆为两个。做四次卷积以后,将得到的答案合并并取模即可。

当然\(MTT\)还有利用\(FFT\)模数计算再用中国剩余定理合并的做法,但第一种做法更加直观。

\(2\)、分治\(FFT\)

有两种分治\(FFT\),先来讲比较简单的第一种。

如果我们有一个长度为\(n\)的数组\(a\),并且希望求:

\[\prod_{i=0}^{n-1}(x+a_i)\]

直接按照暴力计算,是\(O(n^2)\)的(因为每一个只有两项,所以一次暴力乘法只有\(O(n)\))。如果我们把乘法用\(FFT\)来实现,我们就得到了\(O(n^2\log n)\)优秀复杂度。

怎么做才会更快呢?

分治往往能带来更加优秀的复杂度。直接利用\(FFT\)之所以慢,是因为相乘的两个多项式次数相差太大,这会非常浪费。

那我们不妨考虑先计算左半部分和右半部分的积。这是两个\(O(n)\)次的多项式,直接用\(FFT\)\(O(n\log n)\)的时间内相乘即可。那么我们的递归式就是:

\[T(n)=2T(n/2)+O(n\log n)\]

解得\(T(n)=O(n\log ^2n)\),复杂度得到了很大优化。

那么再来讲讲\(dark\)的第二种分治\(FFT\)

你有一个下标集合为\(\{1,2,...,n\}\)的数组\(f\),你想要求一个下标集合为\(\{0,1,2,...,n\}\)的数组\(g\),满足:

\[g_i=\sum_{j=1}^{i}f_jg_{i-j}\]

边界条件\(g_0=1\)

看上去直接求好像有点困难,那么我们来考虑分治。我们把数组\(g\)拆为前后两半,显然后一半对前一半是没有影响的,直接递归求解前一半。求解完毕以后我们来计算前一半对后一半的贡献,这时我们直接根据上面的式子\(FFT\)即可,因为此时前后的影响已经被我们用分治消除了。最后我们递归继续后一半的求解。

综上所述,递归式为:

\[T(n)=2T(n/2)+O(n\log n)\]

解得\(T(n)=O(n\log^2 n)\),复杂度较优秀。

\(P.S.\)第二个问题其实有复杂度更优秀的解法,可以参见下面的“多项式求逆”。但是分治的思想更加直观,并且有的类型并不能利用“多项式求逆”来做,因此分治\(FFT\)的作用还是很大的。

\(3\)、多项式倍增(思想)

倍增是接下来对许多多项式问题求解的重要方法。

在多项式中可能有一些我们要求的多项式次数是无限的,那么一般我们只需要知道它的前\(n\)项,即\(\mod x^n\)的结果即可。直接求解或许也比较困难,此时可以考虑倍增。

我们先用简单的方法求出\(\mod x\)的平凡情况,然后就只需要考虑如何从\(\mod x^k\)
的结果\(\widehat f\)推到\(\mod x^{2k}\)的结果\(f\)即可。一般来说,利用\((f-\widehat f)^2\equiv 0 (\mod x^{2k})\)这个性质就可以得到很方便的求解方法。

\(4\)、多项式求逆

多项式求逆是这样一个问题,已知一个\(n\)次多项式\(f\),我们希望求一个\(n\)次多项式\(g=f^{-1}\),即:

\[f*g\equiv 1(\mod x^n)\]

显然要求\(f\)的常数项不为\(0\)。那么在\(\mod x\)意义下,直接求得\(g_0=f_0^{-1}\)

现在我们考虑从\(\mod x^k\)的结果\(\widehat g\)推出\(\mod x^{2k}\)的结果\(g\)。我们有:

\[(g-\widehat g)^2\equiv 0(\mod x^{2k})\]

把平方展开,得到:

\[g^2-2g\widehat g+\widehat g^2\equiv 0(\mod x^{2k})\]

这个式子好像有点\(dark\),但是我们已经知道\(f*g\equiv 1(\mod x^{2k})\),因此我们对等式两边同时乘以\(f\),得到:

\[g-2\widehat g+f\widehat g^2\equiv 0(\mod x^{2k})\]

移项,得:

\[g\equiv 2\widehat g-f\widehat g^2(\mod x^{2k})\]

就可以直接进行倍增。递归式为\(T(n)=T(n/2)+O(n\log n)\),解得\(T(n)=O(n\log n)\)

多项式求逆也是很多多项式问题的基础,在接下来的几种多项式黑科技中起到了很大的作用。

那么再来举一个应用多项式求逆的例子,就是在之前的“分治\(FFT\)”里提到的第二个问题。为了保持完整我们再陈述一遍:

你有一个下标集合为\(\{1,2,...,n\}\)的数组\(f\),你想要求一个下标集合为\(\{0,1,2,...,n\}\)的数组\(g\),满足:

\[g_i=\sum_{j=1}^{i}f_jg_{i-j}\]

边界条件\(g_0=1\)

我们先想办法把上面的式子化成普通的卷积形式。我们把\(j\)的枚举范围从\(1,2,...,i\)改为卷积形式的\(0,1,2,...,i\),此时我们发现多计算了\(f_0g_i\)这一项。那么我们不妨令\(f_0=0\),我们就消去了这一项的贡献。同时注意到作为边界的\(g_0\)如果直接用这个卷积形式计算会得到\(0\),那么我们可以强制将结果加\(1\)。经过这番操作卷积的答案就为\(g\)了。于是我们得到了非常优美的式子:

\[g=fg+1\]

我们移项,得到:

\[(1-f)g=1\]

利用多项式求逆求出\((1-f)^{-1}(\mod x^{n+1})\),在两边同时乘上,于是得到了:

\[g\equiv \frac{1}{1-f}(\mod x^{n+1})\]

由于我们只要知道\(g\)的前\(n+1\)项,因此\(\mod x^{n+1}\)是没有关系的,于是我们就利用多项式求逆在\(O(n\log n)\)的时间内解决了这个问题。

\(5\)、多项式除法、取模

给你一个\(n\)次多项式\(f\),以及一个\(m\)次多项式\(g\)\(n>m\)),我们希望求一个\(n-m+1\)次多项式\(q\)以及一个\(m-1\)次多项式\(r\),满足:

\[f=qg+r\]

那么我们称\(q\)\(f\)除以\(g\)的商,而称\(r\)\(f\)除以\(g\)的余数。

现在我们来考虑如何求\(q\)\(r\)。我们先定义\(n\)次多项式\(f\)的一种变换\(f^R\)

\[f^R=f(\frac{1}{x})*x^{n-1}\]

不难看出\(f^R\)即是将\(f\)的系数反转一下。因此我们可以在\(O(n)\)的时间内完成这个变换。

那么我们来推式子,我们不妨用\(\frac{1}{x}\)替换多项式内的\(x\),这样的结果显然依旧正确:

\[f(\frac{1}{x})=q(\frac{1}{x})g(\frac{1}{x})+r(\frac{1}{x})\]

接着考虑在两边同乘\(x^{n-1}\),得到:

\[f(\frac{1}{x})*x^{n-1}=q(\frac{1}{x})*x^{m-1}*g(\frac{1}{x})*x^{n-m}+r(\frac{1}{x})*x^{m-2}*x^{n-m+1}\]

不难发现我们已经有意为那个变换做好了准备,那么我们将四个多项式都用变换来代替:

\[f^R=q^Rg^R+r^R*x^{n-m+1}\]

我们考虑消去最后一项,那么不妨把式子放到\(\mod x^{n-m+1}\)的意义下。此时最后一项肯定为\(0\),于是就消失了:

\[f^R\equiv q^Rg^R(\mod x^{n-m+1})\]

我们发现既然\(q\)\(n-m+1\)次的,那么\(q^R\)也是\(n-m+1\)次的,\(\mod x^{n-m+1}\)对其没有影响。于是我们求\(g^R\)的逆,就得到:

\[q^R\equiv \frac{f^R}{g^R}(\mod x^{n-m+1})\]

于是我们就求得了\(q^R\),然后简单地再做一次变换就得到了\(q\)。此时算\(r\)就很方便了,直接计算\(f-qg\)即可。

\(6\)、多项式求导、积分

这是两个很简单的变换,是为了下面的内容做好准备。

\(f\)是一个\(n\)次多项式,那么\(f\)的导数\(f'\)就是一个\(n-1\)次多项式,并且满足:

\[f'_i=(i+1)f_{i+1}\]

直接\(O(n)\)计算即可。

\(f\)是一个\(n\)次多项式,那么\(f\)的积分\(\int f\)就是一个\(n+1\)次多项式,并且满足:

\[\int f_i=\frac{f_{i-1}}{i}\]

边界条件\(\int f_0=0\)

同样\(O(n)\)计算即可。

\(7\)、多项式\(\ln\)

事情开始变得诡异起来了。

多项式求\(\ln\)是这样一个问题,给你一个\(n\)次多项式\(f\),满足\(f_0=1\),你需要求一个\(n\)次多项式\(g\),满足:

\[g\equiv \ln f(\mod x^n)\]

看到这个是不是一下子有点懵啊...没关系,我们来冷静分析。函数\(\ln(x)\)的一个特点就是\(\ln'(x)=\frac{1}{x}\),这就一下子好办了,我们把这个结论照搬到多项式上面去,对上面的等式两边求导,得到:

\[g'\equiv \frac{1}{f}(\mod x^n)\]

这是不是非常简单啊,直接多项式求逆就得到了\(g'\),那么我们再将等式两边积分,就得到:

\[g\equiv \int \frac{1}{f}(\mod x^n)\]

不过还有一个小疑问,求导一次再积分一次不是会丢掉常数项吗,这怎么办呢。其实没关系,我们已经保证\(f_0=1\),而\(\ln 1=0\),因此\(g\)的常数项就是\(0\)。于是我们就做完了。

\(8\)、多项式牛顿迭代、泰勒展开(思想)

接下来我们讲一下多项式牛顿迭代和泰勒展开,为接下来的工作做准备。话说多项式真是强啊什么都能套上去。

先来讲牛顿迭代。

我们知道,如果我们希望在实数域内求得某个处处可导函数\(f(x)\)的零点的近似值,我们就可以用牛顿迭代来解决。我们随意选择一个初值,设其为\(x_0\),然后开始迭代。每一次从\(x_i\)迭代到\(x_{i+1}\),我们的精度会得到很大提升,迭代式子为:

\[x_{i+1}=x_i-\frac{f(x_i)}{f'(x_i)}\]

其实就相当于\(x_{i+1}\)\(f(x)\)\(x_i\)处的这条切线和横轴的交点,可以自己推一下式子证明。

我们将牛顿迭代应用到多项式上,具体来说:

我们给出一个\(n\)次多项式\(f\)以及一个以多项式为参数,并且结果也是一个多项式的函数\(G\),并希望计算出一个\(n\)次多项式\(g\),满足:

\[G(g)\equiv f(\mod x^n)\]

把问题简单转化一下,就是希望求得\(G-f\)的零点了。那么我们依然先求出\(\mod x\)意义下的简单结果,接着套用牛顿迭代的公式。设上一次迭代的答案为\(\widehat g\),我们就得到:

\[g=\widehat g-\frac{G(\widehat g)-f}{G'(\widehat g)}\]

为什么求导的时候多项式\(f\)会消失呢?这是因为\(G\)是关于多项式的函数,其导数反映的是当多项式变化时的变化幅度,因此不变的多项式\(f\)就被看作时常数项了。

同时我们可能还有一个疑问:牛顿迭代不是用来提高精度的吗?怎么在多项式上应用呢?我们感性理解一下,假设\(\widehat g\)\(\mod x^k\)意义下的结果,那么迭代式子显然可以得到一个\(2k\)次多项式,此时我们给出结论:通过这个牛顿迭代的式子,我们可以得到\(\mod x^{2k}\)意义下的结果。对它的证明将放到泰勒展开的讲解内。

于是我们就可以发现,利用牛顿迭代公式,我们可以做到类似倍增的效果。那么许多看似复杂的问题就可以解决了。

现在来讲一下多项式的泰勒展开。

我们刚刚已经得到了牛顿迭代在多项式上的应用,但是对于它的正确性,我们却是一知半解。幸好我们还有一种可以较简单的进行证明的方法:多项式泰勒展开。同时利用泰勒展开我们还可以获得一些问题求解的思路。

我们已经知道泰勒展开式为:

\[f(x)=\sum_{i=0}^{\infty}\frac{f^{(i)}(x_0)}{i!}*(x-x_0)^i\]

我们可以证明其对以多项式为参数的函数也成立,这和一般情况是一样的。那么我们依然考虑之前牛顿迭代所讲的问题,我们以\(\mod x^k\)意义下的答案\(\widehat g\)代入\(x_0\),求\(\mod x^{2k}\)意义下的答案\(g\),那么我们有:

\[G(g)-f\equiv G(\widehat g)-f+G'(\widehat g)*(g-g_0)+...(\mod x^{2k})\]

我们再次利用这个性质:\((g-\widehat g)^2\equiv 0(\mod x^{2k})\),那么泰勒展开式中除了前两项以外都变成了\(0\),于是便不用再考虑后面了,得到:

\[G(g)-f\equiv G(\widehat g)-f+G'(\widehat g)*(g-\widehat g)(\mod x^{2k})\]

而我们又有\(G(g)-f\equiv 0(\mod x^{2k})\),于是左边就为\(0\),我们移项得:

\[-G'(\widehat g)*(g-\widehat g)\equiv G(\widehat g)-f(\mod x^{2k})\]

两边同除\(-G'(\widehat g)\)

\[g-\widehat g\equiv -\frac{G(\widehat g)-f}{G'(\widehat g)}(\mod x^{2k})\]

再将\(\widehat g\)加到右边:

\[g\equiv \widehat g-\frac{G(\widehat g)-f}{G'(\widehat g)}(\mod x^{2k})\]

我们此时发现这就是牛顿迭代的公式,于是就完成了对牛顿迭代正确性的证明。当然泰勒展开的作用不只是证明牛顿迭代,我们在做题时可能推出一个关于某个多项式的奇怪式子,如果你能发现它正好是一个常见函数的泰勒展开,就可以用专门求这个函数的方法来解决——例如我们即将要讲的\(\exp\)

猜你喜欢

转载自www.cnblogs.com/Mr-Spade/p/9723461.html