多项式全家桶

Posted newbielyx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多项式全家桶相关的知识,希望对你有一定的参考价值。

多项式乘法

(FFT Rightarrow) 传送门

(NTT Rightarrow) 传送门

(FFT)

void FFT(int lim, Complex *a, int op) {
    for (int i = 0; i < lim; ++i)
        if (i < r[i]) swap(a[i], a[r[i]]);
    for (int len = 2; len <= lim; len <<= 1) {
        int mid = len >> 1;
        Complex Wn = {cos(Pi / mid), op * sin(Pi / mid)};
        for (int i = 0; i < lim; i += len) {
            Complex w = {1, 0};
            for (int j = 0; j < mid; ++j, w = w * Wn) {
                Complex x = a[i + j], y = w * a[i + j + mid];
                a[i + j] = x + y;
                a[i + j + mid] = x - y;
            }
        }
    }
}

(NTT)

ll root(const ll p) {
    for (int i = 2; i <= p; ++i) {
        int x = p - 1;
        bool flag = true;
        for (int k = 2; k * k <= p - 1; ++k) if (!(x % k)) {
            if (ksm(i, (p - 1) / k) == 1) {
                flag = false;
                break;
            }
            while (!(x % k)) x /= k;
        }
        if (flag && (x == 1 || ksm(i, (p - 1) / x) != 1)) return i;
    }
}
void NTT(int lim, ll *a, int op) {
    for (int i = 0; i < lim; ++i)
        if (i < r[i]) swap(a[i], a[r[i]]);
    for (int len = 2; len <= lim; len <<= 1) {
        int mid = len >> 1;
        ll Wn = ksm(op == 1 ? G : Gx, (mod - 1) / len);
        for (int i = 0; i < lim; i += len) {
            ll w = 1;
            for (int j = 0; j < mid; ++j, w = (w * Wn) % mod) {
                ll x = a[i + j], y = w * a[i + j + mid] % mod;
                a[i + j] = (x + y) % mod;
                a[i + j + mid] = (x - y + mod) % mod;
            }
        }
    }
}

多项式求逆

当多项式只有一项时,那么显然 (G_0) 就是 (F_0) 的逆元。

考虑一般情况下,如果我们已知 (F(x) H(x) equiv 1 (mod x^{lceil frac{n}{2} ceil})) ,如何求出 (F(X)G(x) equiv 1(mod x^n))

已知 (F(x) H(x) equiv 1 (mod x^{lceil frac{n}{2} ceil}))

又显然 (F(X)G(x) equiv 1(mod x^{lceil frac{n}{2} ceil}))

(x ^ n) 相当于将次数大于等于 (n) 的项舍去了,模 (x^{lceil frac{n}{2} ceil}) 则相当于舍去了更多的项,所以前者满足,后者一定满足。

将两个式子相减 (F(x)left[ G(x) - H(x) ight] equiv 0 (mod x ^ {lceil frac{n}{2} ceil}))

(G(x) - H(x) equiv 0 (mod x ^ {lceil frac{n}{2} ceil}))

然后将两边·平方一下
[ G^2(x) - 2G(x)H(x)+ H^2(x) equiv 0 (mod x^{lceil frac{n}{2} ceil}) ]
由于 (G(x)-H(x)) 在 模 (x^{lceil frac{n}{2} ceil}) 下为 (0),所以这个式子的结果的 (0)(lceil frac{n}{2} ceil - 1) 次项系数都为 (0)

而平方之后,对于结果的 (i) 次项((0 le i le 2 imes lceil frac{n}{2} ceil - 1)),其系数 (a_i=sum limits_{j=0}^{i} a_j a_{i-j}), 其中 (a_j)(a_{i-j}) 必定至少有一项小于等于 (lceil frac{n}{2} ceil - 1),所以可以得知,平方之后的式子在模 (x^n) 意义下也为 (0)
[ G^2(x) - 2G(x)H(x)+ H^2(x) equiv 0 (mod x^{n}) ]
给式子乘上一个 (F(x)),得到
[ F(x)G^2(x) - 2F(x)G(x)H(x)+ F(x)H^2(x) equiv 0 (mod x^{n}) ]
由多项式乘法逆的定义 (F(x)G(x)equiv 0(mod x ^n))可以得到
[ G(x) - 2H(x)+ F(x)H^2(x) equiv 0 (mod x^{n}) ]
再移项
[ G(x) equiv 2H(x)+ F(x)H^2(x) (mod x^{n}) ]
于是就可以不断倍增,求出多项式乘法逆。

void polyinv(int len, int *A, int * B) {
    if (len == 1) {
        B[0] = fpow(A[0], P - 2);
        return;
    }
    static int tmp[_];
    polyinv((len + 1) >> 1, A, B);
    int lim = 1, k = 0;
    while (lim < (len << 1)) lim <<= 1, ++k;
    for (int i = 0; i < lim; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (k - 1));
    copy(A, A + len, tmp);
    fill(tmp + len, tmp + lim, 0);
    NTT(lim, tmp, 1);
    NTT(lim, B, 1);
    for (int i = 0; i < lim; ++i)
        B[i] = (2ll - 1ll * B[i] * tmp[i] % P + P) * B[i] % P;
    NTT(lim, B, -1);
    fill(B + len, B + lim, 0);
}

多项式除法

以上是关于多项式全家桶的主要内容,如果未能解决你的问题,请参考以下文章

多项式全家桶(持续更新中)

学习笔记多项式全家桶(包含全套证明)

多项式全家桶

多项式全家桶

多项式全家桶

多项式全家桶