[洛谷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;
}