[洛谷P4238] 多项式乘法逆

给定 \(n-1\) 次多项式 \(F(x)=\sum_{i=0}^{n-1}a_ix^i\),求出多项式 \(G(x)=\sum_{i=0}^{n-1}b_ix^i\),使得 \(F(x)*G(x)\equiv 1\pmod{x^n}\),系数对 \(998244353\) 取模。\((1\leq n\leq 10^5,0\leq a_i\leq 10^9)\)

题解

如果 \(F(x)=a_0\), 只有常数项,显然 \(G(x)=a_0^{-1}\)
\(H(x)\equiv G(x)\pmod{x^{\lceil\frac{2}{n}\rceil}}\),则有

\[F(x)*H(x)\equiv 1 \pmod{x^{\lceil\frac{2}{n}\rceil}}\\ F(x)*G(x)\equiv 1 \pmod{x^{\lceil\frac{2}{n}\rceil}}\\ F(x)*(H(x)-G(x))\equiv 0 \pmod{x^{\lceil\frac{2}{n}\rceil}}\\ H(x)-G(x)\equiv 0 \pmod{x^{\lceil\frac{2}{n}\rceil}}\\ H^2(x)-2H(x)*G(x)+G^2(x)\equiv 0 \pmod{x^n}\\ F(x)*H^2(x)-2H(x)+G(x)\equiv 0 \pmod{x^n}\\ G(x)\equiv H(x)*(2-F(x)*H(x)) \pmod{x^n} \]

所以我们只需要进行倍增,每次做一下NTT即可。时间复杂度 \(O(n\log n)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType& T) {
    elemType X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    T = (w ? -X : X);
}

inline LL ExPow(LL b, LL n, LL MOD) {
    if (MOD == 1) return 0;
    LL x = 1;
    LL Power = b % MOD;
    while (n) {
        if (n & 1) x = x * Power % MOD;
        Power = Power * Power % MOD;
        n >>= 1;
    }
    return x;
}

namespace Poly {
    int r[2100010];
    LL buf[2100010];
    int L, limit;
    const LL P = 998244353, G = 3, Gi = 332748118;


    void NTT(LL* A, int type) {
        for (int i = 0; i < limit; i++)
            if (i < r[i]) swap(A[i], A[r[i]]);
        for (int mid = 1; mid < limit; mid <<= 1) {
            LL Wn = ExPow(type == 1 ? G : Gi, (P - 1) / (mid << 1), P);
            for (int j = 0; j < limit; j += (mid << 1)) {
                LL w = 1;
                for (int k = 0; k < mid; k++, w = (w * Wn) % P) {
                    int x = A[j + k], y = w * A[j + k + mid] % P;
                    A[j + k] = (x + y) % P,
                        A[j + k + mid] = (x - y + P) % P;
                }
            }
        }
        if (type == 1) return;
        LL inv_limit = ExPow(limit, P - 2, P);
        for (int i = 0; i < limit; ++i)
            A[i] = (A[i] * inv_limit) % P;
    }

    void PolyInv(LL* a, LL* inv, int N) {
        if (N == 1) { inv[0] = ExPow(a[0], P - 2, P);return; }
        PolyInv(a, inv, (N + 1) >> 1);
        for (limit = 1; limit <= (N << 1); limit <<= 1);
        for (int i = 0; i < limit; ++i) {
            r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (limit >> 1) : 0);
            buf[i] = (i < N ? a[i] : 0);
        }
        NTT(buf, 1);NTT(inv, 1);
        for (int i = 0; i < limit; ++i)
            inv[i] = (2LL - buf[i] * inv[i] % P + P) % P * inv[i] % P;
        NTT(inv, -1);
        fill(inv + N, inv + limit, 0);
        return;
    }
}
LL a[2100010], b[2100010];
int n, m;

int main() {
    Read(n);
    for (int i = 0;i < n;++i)
        Read(a[i]);
    Poly::PolyInv(a, b, n);
    for (int i = 0;i < n;++i)
        printf("%lld ", b[i]);
    printf("\n");

    return 0;
}
posted @ 2021-03-06 20:16  AE酱  阅读(64)  评论(0编辑  收藏  举报