分治 FFT 模板的三種過法

生成函數做法

\[\begin{align} f[i] &= \sum_{j=1}^i f[i-j]g[j] \\ f[i] & =\sum_{j=0}^{i-1}f[(i-1)-j]g[j+1] \end{align} \]

把 g 整體左移一位後:

\[\begin{align} f[i] & =\sum_{j=0}^{i-1}f[(i-1)-j]g[j] \\ f[i] &= (f*g)[i-1] \\ &i > 0 \end{align} \]

\(f(z) = z*f(z)*g(z) + 1\)

這相當於 g 不需要左移。

於是 \(f(z) = f(z)g(z) + 1\)

在膜 \(x^n\) 意義下, \(f(z) = \dfrac 1{1-g(z)}\)

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int N = 4e5 + 233, mo = 998244353;
LL ksm(LL a, LL b) {
	LL res = 1ll;
	for(; b; b>>=1, a=a*a%mo)
		if(b & 1) res = res*a%mo;
	return res;
}
const int g = 3, ig = ksm(g, mo - 2);

int rv[N];
void NTT(LL *a, int n, int type) {
	for(int i = 0; i < n; ++i) if(i < rv[i]) swap(a[i], a[rv[i]]);
	for(int m = 2; m <= n; m = m << 1) {
		LL w = ksm(type == 1 ? g : ig, (mo - 1) / m);
		for(int i = 0; i < n; i += m) {
			LL tmp = 1ll;
			for(int j = 0; j < (m >> 1); ++j) {
				LL p = a[i + j], q = tmp * a[i + j + (m >> 1)] % mo;
				a[i + j] = (p + q) % mo, a[i + j + (m >> 1)] = (p - q + mo) % mo;
				tmp = tmp * w % mo;
			}
		}
	}
	if(type == -1) {
		LL Inv = ksm(n, mo - 2);
		for(int i = 0; i < n; ++i) a[i] = a[i] * Inv % mo;
	}
}

int n;
LL G[N], f[N], t[N];

void poly_inv(int deg, LL *a, LL *b) {
	if(deg == 1) { b[0] = ksm(a[0], mo - 2); return;}
	poly_inv((deg + 1) >> 1, a, b);
	int len = 1; while(len < (deg << 1)) len = len << 1;
	for(int i = 0; i < deg; ++i) t[i] = a[i];
	for(int i = deg; i < len; ++i) t[i] = 0ll;
	for(int i = 1; i < len; ++i) rv[i] = (rv[i>>1]>>1) | (i&1 ? len>>1 : 0);
	NTT(t, len, 1), NTT(b, len, 1);
	for(int i = 0; i < len; ++i) b[i] = b[i] * (2ll - t[i] * b[i] % mo) % mo;
	NTT(b, len, -1);
	for(int i = deg; i < len; ++i) b[i] = 0ll;
}

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n-1; ++i) scanf("%lld", &G[i]), G[i]%=mo, G[i] = (mo - G[i]);
	G[0] = 1ll;
	poly_inv(n, G, f);
	for(int i = 0; i < n; ++i) cout << (f[i] % mo + mo) % mo << ' ';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章