zoukankan      html  css  js  c++  java
  • 多项式运算的一些技术

    昨天白天看了看多项式的一些东西,完全看不懂,于是晚上学一学多项式的基本运算。

    以下用字母 (f) 表示多项式,带下标的字母表示系数 (f_i)([n]) 表示 ( ext{mod}~x^n)

    加减法

    [(f+g)(x)=sum _{i=0}^infty (f_i+g_i)x^i ]

    直接加法是 (O(n)) 的。由上式也可以看出,点值之和是和的点值。

    乘法

    多项式意义下的乘法一般是线性卷积。

    可以用叉乘表示,也可以简写

    [fg=(f imes g)(x)=sum _ksum _isum _j[i+j=k]f_ig_jx^k ]

    [(f imes g)_k=sum _{i+j=k}f_ig_j ]

    这可以用计算循环卷积的 fft 或 ntt 通过倍长实现线性卷积。

    除法

    [frac{f}{g}=f imes g^{-1} ]

    问题就变成求一个多项式的逆元。

    一个多项式是否有可能有一个完全的逆元呢?即一个多项式 (f) ,是否存在 (g) 使得 ((f imes g)(x)=1)

    对于次数大于 0 的多项式 (f) ,不存在有限长度的符合要求的 (g) ,因为 (f) 的最高次和 (g) 的最高次总是无法消掉的。

    那么就讨论在有限的位中的逆元,因为一般我们要求的都是序列的前一些项,之后的是不需要考虑的。

    问题变成了已知一个 (g) ,求 (f) 使得

    [egin{aligned} fgequiv 1 &&[n] end{aligned} ]

    即在 ( ext{mod}~x^n) 的意义下求这个东西。

    这类在对 (x^k) 取模意义下求的问题,一般用倍增解决。倍增的方式可以统一地用牛顿迭代得到。

    设我们已经求出了 ( ext{mod}~x^frac{n}{2}) 的多项式 (f_0) ,拓展到 ( ext{mod}~x^n)

    设一个函数 (H(x)) ,为了方便计算,让它在对应解的位置取 0 。在这个问题中,(H(x)=frac{1}{x}-g) ,这样对于符合要求的 (f) ,有 (H(f)=frac{1}{f}-g=g-g=0)

    (f) 处对 (H) 进行泰勒展开,用 (f_0) 来逼近它,可得

    [H(f)=sum _{i=0}^infty frac{H^{(i)}(f_0)(f-f_0)^i}{i!} ]

    这里有一个简单的结论:(f)(f_0) 的前 (frac{n}{2}) 位是相同的。这是因为

    [egin{aligned} f_0gequiv 1&&[frac{n}{2}] \ fgequiv 1 && [n] \ (f-f_0)gequiv 0 &&[frac{n}{2}] end{aligned} ]

    (g e 0) ,得到结论。

    也就是说,((f-f_0)^2) 的最低非 0 位至少在 (x^n) ,而我们要计算的是 ( ext{mod}~x^n) 意义下的 (f) ,所以后面的项在当前是没有用的。

    [egin{aligned} H(f)equiv H(f_0)+H'(f_0)(f-f_0) && [n] end{aligned} ]

    由于我们要求的 (f)( ext{mod}~x^n) 的意义下,使得 (H(f)=frac{1}{f}-g=0) ,所以有

    [egin{aligned} H(f_0)+H'(f_0)(f-f_0)equiv 0 && [n]\ end{aligned} ]

    我们已经得到了解的一般形式。

    [egin{aligned} fequiv f_0-frac{H(f_0)}{H'(f_0)} && [n] end{aligned} ]

    在上面的过程中 (H) 是一个抽象的,满足 (H(f)equiv 0 mod x^n) 的函数,它可以是任何函数。

    代入我们这里的 (H(x)=frac{1}{x}-g) ,并把 (g) 看作一个常量,那就有

    [egin{aligned} fequiv f_0-frac{frac{1}{f_0}-g}{-f_0^{-2}}&& [n] \ fequiv 2f_0-gf_0^2 && [n] end{aligned} ]

    它只涉及到递归求出 (f_0) 和长度为 (n) 的乘法,即复杂度为

    [T(n)=T(frac{n}{2})+O(nlog n)=O(nlog n) ]

    一个需要注意的地方:可以发现 (f) 的式子后面有 (gf_0^2) 这一项,意味着可能会出现多余的项,需要去掉。

    由上述算法可以看出,多项式有模 (x^n) 意义下的逆元,等价于常数项有逆元。

    乘方

    快速幂+乘法方法,(O(nlog ^2n))

    也可以用下面讲到的方法做到 (O(nlog n))

    开根

    即求 (f) 使得

    [egin{aligned} f^kequiv g && [n] end{aligned} ]

    运用上面的通用方法

    [egin{aligned} fequiv f_0-frac{H(f_0)}{H'(f_0)} && [n] end{aligned} ]

    构造函数 (H(x)=x^k-g) ,展开可得

    [egin{aligned} f&equiv f_0-frac{f_0^k-g}{kf_0^{k-1}} && [n] \ f&equiv frac{k-1}{k}f_0+frac{g}{kf_0^{k-1}} && [n] end{aligned} ]

    这里使用了乘法,加法和(除法)求逆,复杂度为 (O(nlog ^2 n))

    可以发现,多项式有模 (x^n) 意义下的根,等价于常数项有根。

    可以用下面的方法做到 (O(nlog n))

    (exp & ln)

    终于到了这个时刻。

    实数的开根和乘方,两种指数上的运算,可以用对数和指数的方法,变成加减法。多项式也如此。

    对一个多项式 (f) ,定义 (exp f) (即 (e^f) ),为泰勒展开的形式

    [exp f=sum _{k=0}^infty frac{f^k}{k!} ]

    定义 (ln)(exp) 的逆运算,即 (ln (exp f)=f)

    一般我们是不会需要上面的无穷形式的,而是需要得到前 (n) 位,所以求解仍然在 ( ext{mod}~x^n) 意义下进行。

    如何求这两个东西呢?

    (ln)

    [egin{aligned} fequiv ln g && [n] end{aligned} ]

    对两边进行求导

    [egin{aligned} f'equiv frac{g'}{g} && [n] \ fequiv int frac{g'}{g} && [n] end{aligned} ]

    多项式的求导和积分都是 (O(n)) 的,其中用到的逆元是 (O(nlog n)) 的,所以复杂度为 (O(nlog n))

    (exp)

    (f) 使得

    [egin{aligned} ln fequiv g&& [n] end{aligned} ]

    运用通用方法,设 (H(x)=ln x-g) ,那么

    [egin{aligned} f&=f_0-frac {H(f_0)}{H'(f_0)} && [n] \ f&=f_0-frac {ln f_0-g}{frac{1}{f_0}} && [n] \ f&=f_0(1-ln f_0+g) && [n] end{aligned} ]

    后记

    大概就是这样啦

    主要就是牛顿迭代倍增的方法和神奇的 (ln)(exp)

    最近会做一些多项式相关的题,研究一下生成函数吧。

  • 相关阅读:
    Linux环境下安装python3
    软件测试类型
    系统测试分类
    测试级别
    测试对象的介绍
    软件测试基本介绍
    简易留言板(还有一些小bug,修复ing...)
    Hosting static website on AWS
    Add a dependency in Android Studio
    Python good tutorials
  • 原文地址:https://www.cnblogs.com/owenyu/p/7576568.html
Copyright © 2011-2022 走看看