给定 (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 1pmod{x^n}),系数对 (998244353) 取模。((1leq nleq 10^5,0leq a_ileq 10^9))
题解
如果 (F(x)=a_0), 只有常数项,显然 (G(x)=a_0^{-1})。
设 (H(x)equiv G(x)pmod{x^{lceilfrac{2}{n}
ceil}}),则有
[F(x)*H(x)equiv 1 pmod{x^{lceilfrac{2}{n}
ceil}}\
F(x)*G(x)equiv 1 pmod{x^{lceilfrac{2}{n}
ceil}}\
F(x)*(H(x)-G(x))equiv 0 pmod{x^{lceilfrac{2}{n}
ceil}}\
H(x)-G(x)equiv 0 pmod{x^{lceilfrac{2}{n}
ceil}}\
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(nlog 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("
");
return 0;
}