zoukankan      html  css  js  c++  java
  • 多项式操作汇总

    多项式操作汇总

    最近学了不少多项式的小 trick,感觉不记一下容易忘。那我就把做法都摆在这里吧,代码还是自己去写了。(鉴于所有操作都是建立在 FFT 之上的,所以会写 FFT 的话所有东西的代码都能写出来了

    多项式乘法

    这个就是一切的基础,先把这个代码搞熟后面就都能写啦。

    多项式逆元

    定义多项式 (g(x)) 的逆元 (g^{-1}(x))(以下为了方便简记为 (f(x)))是满足如下等式的多项式:

    [egin{matrix} g(x) cdot f(x) equiv 1 & (mod x^n) end{matrix} ]

    可以想象,模 (x^n) 的意思就是把 (x^{n+1}) 及更高的项都删掉,剩下的部分。为什么我们可以这样做呢?因为在解决实际问题的时候我们都只关心前 (n) 项(即 (x^0 sim x^{n-1}) 的系数)。

    (f(x)) 的方法可能不止一种,但是我觉得用泰勒展开这个方法虽然麻烦但是好记(因为大多数问题可以用它——它是“通解”)。

    注意:以下多项式都会在第一次用 (f(x)) 表示过后就可能省掉后面的 ((x)),你需要知道它是一个多项式。

    我们先构造一个函数 (H(f) = f^{-1} - g)。你没有看错,这个 (H(f)) 函数的自变量就是一个多项式。为什么要这样构造函数呢?因为可以发现当自变量 (f = g^{-1}),即 (f) 就是答案的时候,(H(f) = 0)

    我们用倍增的方法求这个 (f),假设已经求出 (f_0(x))(f)(lceil frac{n}{2} ceil) 项,即

    [egin{matrix} f_0 equiv f & (mod x^{lceil frac{n}{2} ceil}) end{matrix} ]

    现在我们要(f_0)(g) 表示出 (f)。利用我们刚才构造的函数,根据 (f_0) 的定义有

    [egin{matrix} H(f_0) equiv 0 & (mod x^{lceil frac{n}{2} ceil}) end{matrix} ]

    为了实现上面黑体字的目的,我们对 (H(f))(f_0) 处进行泰勒展开(想点进去看的请翻到文章末尾),即用下面这个式子去逼近 (H(f))

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

    注意上面这个等式不是模意义下的,不需要取模它们就相等。

    接下来我们观察一下 ((f-f_0)^i),由于 (f - f_0 equiv 0 (mod x^{lceil frac{n}{2} ceil})),发现当 (i = 2) 时,最高次项平方之后次数一定 (ge n),所以有 (forall i > 1, (f-f_0)^i equiv 0 (mod x^n)),那么上面的泰勒展开的无穷多项就只剩了两项,整理出来就是

    [egin{matrix} H(f) equiv H(f_0) + H'(f_0)(f - f_0) & (mod x^n) \\ ecause H(f) equiv 0 & (mod x^n) \\ herefore H(f_0) + H'(f_0)(f - f_0) equiv 0 & (mod x^n) end{matrix} ]

    移项得到

    [egin{matrix} f equiv f_0 - frac{H(f_0)}{H'(f_0)} & (mod x^n) end{matrix} ]

    至此我们得到了牛顿迭代的公式,以后可以记它,就不用每次都泰勒展开了。接下来的工作就是把刚才构造的 (H(f)) 带进去。

    [egin{matrix} f equiv 2f_0 - gf_0 & (mod x^n) end{matrix} ]

    递归下去,再用这个式子回溯,就求出来啦!

    时间复杂度:(T(n) = T(frac{n}{2}) + O(nlog n) = O(nlog n)),发现这个小秘密后,我们可以无限套,理论复杂度不变233

    多项式除法 & 取模

    注意这里的除法不是在模意义下的!所以它会有商和余数,即如果我要求 (frac{A(x)}{B(x)}),我就是要求两个多项式 (D(x))(R(x)),使得它们满足下面这样一个等式

    [A(x) = B(x)D(x) + R(x) ]

    现在我们记 (n)(A) 的次数,(m)(B) 的次数,那么有 (D) 的次数为 (mathrm{max}(n - m, 0))(R) 的次数 (le m - 1)

    (F(x)) 的次数为 (t)(F^R(x) = F(frac{1}{x}) cdot x^t),直观理解就是把 (F) 的系数反转一下。

    接下来将 (frac{1}{x}) 带入到原式中,再两边同乘 (x^n),看看会发生什么

    [x^nA(frac{1}{x}) = x^{m}B(frac{1}{x}) cdot x^{n-m}D(frac{1}{x}) + x^{n-m+1} cdot x^{m-1}R(frac{1}{x}) \\ herefore A^R(x) = B^R(x)D^R(x) + x^{n-m+1}R^R(x) ]

    如果我们将新的等式放在模 (x^{n-m+1}) 的意义下,(R(x)) 就被消掉了!与此同时 (D^R(x)) 最高次为 (x^{n-m}),故不会受到任何影响,即模意义下求出的 (D^R(x)) 与非模意义下的完全相同。

    [egin{matrix} A^R(x) equiv B^R(x)D^R(x) & (mod x^{n-m+1}) \\ herefore D^R(x) equiv A^R(x)[B^R(x)]^{-1} & (mod x^{n-m+1}) end{matrix} ]

    (D(x)) 就是 (D^R(x)) 反转一下系数,把 (D(x)) 代到最初的式子里就能得到 (R(x)) 了。

    多项式多点求值

    任务:给出多项式 (F(x)) 和集合 ({ x_1, x_2, cdots , x_n }),要求返回一个集合 ({ F(x_1), F(x_2), cdots , F(x_n) })

    构造多项式 (A(x) = (x - x_1)(x - x_2)cdots(x - x_n)),令 (G(x) equiv F(x) (mod A(x))),那么对于 (forall i in [1, n], G(x_i) = F(x_i))

    为什么呢?因为

    [F(x) = A(x)D(x) + G(x) ]

    (forall i in [1, n], A(x_i) = 0, herefore F(x_i) = G(x_i))

    于是就可以分治了。令 (A_l(x) = prod_{i = 1}^{lfloor frac{n}{2} floor} { (x - x_i) }, A_r(x) = prod_{i = lfloor frac{n}{2} floor + 1}^n { (x - x_i) }),然后把 (F(x) mod A_l(x))(F(x) mod A_r(x)) 扔下去递归了。

    时间复杂度:(O(n log^2 n))

    多项式 ln & exp

    应该有不少人好奇这两个操作的组合意义是什么。事实上这个问题我并不是很清楚,我们也许可以通过泰勒展开后的系数研究一下它的组合意义,但它们的价值主要不在于组合意义,而在于其他方面的应用。

    具体应用在讲完做法后立刻就会有一个,所以不必着急,我们先看看多项式取 ln 怎么求。

    多项式取 ln

    注意到这样一个等式

    [(ln f(x))' = frac{f'(x)}{f(x)} ]

    于是积分一下就可以轻易地求出 (ln f(x))

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

    其中,求导和积分都能在 (O(n)) 时间内求出,所以总时间复杂度 (O(n))

    细心的读者一定会问:积分之后,常数项如何确定?注意到这里的 ([x^0]f(x)) 必须为 (1),也就是说 ([x^0] ln f(x)) 一定是 (0),那么积分完后常数项为 (0) 就好了。(如果 ([x^0]f(x) e 1) 怎么求?QAQ 我也不会,因为我们似乎很难找到 (ln c (c > 0)) 在剩余系下的表示……)

    多项式求 exp

    我们要求这样的一个函数 (f(x)),满足

    egin{matrix}
    f(x) equiv e^{g(x)} & (mod x^n)
    end{matrix}

    两边取对数,我们有

    egin{matrix}
    ln f(x) equiv g(x) & (mod x^n)
    end{matrix}

    我们还是考虑倍增求 (f),套用上面泰勒展开推出来的结果,构造函数 (H(f) = ln f - g),令 (f_0 equiv f (mod x^{lceil frac{n}{2} ceil})),于是得到

    egin{matrix}
    f equiv f_0 - frac{ln f_0 - g}{f_0^{-1}} & (mod x^n) \
    f equiv f_0(1 - ln f_0 + g) & (mod x^n)
    end{matrix}

    这样就 (O(n log n)) 解决啦,你会发现求 exp 其实依赖于求 ln。同样地我们只能求 ([x^0]g(x) = 0)(e^{g(x)})

    接下来就是一个经典的应用。

    多项式乘方

    (f(x)) 满足

    egin{matrix}
    f(x) equiv g(x) ^ k & (mod x^n)
    end{matrix}

    指数相关,考虑两边取对数

    egin{matrix}
    ln f(x) equiv k ln g(x) & (mod x^n) \
    f(x) = e^{k ln g(x)} & (mod x^n)
    end{matrix}

    这就解决了?别忘了常数项的问题,问题有两个:

    • ([x^0]g(x) > 1),我们可以将常数项提出来,得到 (g'(x))(注意不是导数,这个就是 (g(x)) 的每项乘上常数项的逆元),那么问题变成了求 ((g'(x))^k c^k)(c) 代表常数项,就是在上面的过程进行完后每项乘上 (c^k) 即可;
    • ([x^0]g(x) = 0),先位移到常数项不为 (0),即得到 (g'(x) = frac{g(x)}{x^d})(d) 表示前缀连续 (0) 的个数,那么问题变成了求 ((g'(x))^k x^{kd}),就是上面的过程进行完后再位移 (kd) 位即可。

    至此多项式乘方就完整地解决了。

  • 相关阅读:
    希尔排序算法
    java面向对象的栈 队列 优先级队列的比较
    java不用任何已有方法完全自写的去重法
    java面向对象的冒泡排序,选择排序和插入排序的比较
    java面向对象的有序数组和无序数组的比较
    Truncated incorrect DOUBLE value:
    laradock 安装多php版本
    graph-composer, 面向 composer.json的依赖图可视化( PHP + Composer )
    php基础
    php通过curl调用webservice
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/8274115.html
Copyright © 2011-2022 走看看