P4238 【模板】多项式乘法逆

#include <cstdio> 
#include <iostream>
#define re register
using namespace std;
typedef long long LL;

const int N = 3e5 + 5, P = 998244353, g = 3;
int rev[N], n;
LL a[N], b[N], c[N];

inline int fpow(LL x, int y)
{
	LL res = 1;
	for(; y; y >>= 1, x = x * x % P) if (y & 1) res = res * x % P;
	return res;
}

inline void NTT(LL *a, int len, int inv)
{
	if (len == 1) return;
	for(re int i = 1; i < len; i++) if (i < rev[i]) swap(a[i], a[rev[i]]);
	for(re int mid = 1, I; mid < len; mid <<= 1)
	{
		I = fpow(g, (P - 1) / (mid << 1));
		if (inv == -1) I = fpow(I, P - 2);
		for(re int i = 0, W; i < len; i += mid << 1)
		{
			W = 1;
			for(re int j = 0, x, y; j < mid; j++, W = 1LL * W * I % P)
				x = a[i + j], y = a[i + j + mid] * W % P,
				a[i + j] = (x + y) % P, a[i + j + mid] = (x - y + P) % P;
		}
	}
}

void solve(int n, LL *a, LL *b)
{
	if (n == 1) return void(b[0] = fpow(a[0], P - 2));
	solve((n + 1) >> 1, a, b);
	int len = 1, bit = 0;
	while (len < (n << 1)) len <<= 1, bit++;
	for(re int i = 0; i < len; i++) rev[i] = ((rev[i >> 1] >> 1) | (i & 1) << bit - 1);
	for(re int i = 0; i < n; i++) c[i] = a[i];
	for(re int i = n; i < len; i++) c[i] = 0;
	NTT(c, len, 1), NTT(b, len, 1);
	for(re int i = 0; i < len; i++) b[i] = b[i] * (2LL - b[i] * c[i] % P + P) % P;
	NTT(b, len, -1);
	int inv = fpow(len, P - 2);
	for(re int i = 0; i < n; i++) b[i] = b[i] * inv % P;
	for(re int i = n; i < len; i++) b[i] = 0;
}

int main()
{
	scanf("%d", &n);
	for(re int i = 0; i < n; i++) scanf("%lld", &a[i]);
	solve(n, a, b);
	for(re int i = 0; i < n; i++) printf("%lld ", b[i]);
}
原文地址:https://www.cnblogs.com/leiyuanze/p/15440608.html