Live2D

$\Theta(n\log n)$ 的对分治 FFT 的优化

还是考虑分治,对于 \([0,r]\) 我们还是先考虑 \([0,mid]\)\([mid+1,r]\) 的贡献,再考虑 \([mid+1,r]\)\([mid+1,r]\) 的贡献,你发现就是你刚才求出来的东西再乘上前面一半的多项式,证明可以考虑你的系数转移式,可以发现跟 \(f\) 的转移式相同。

对于 \(f_0\not= 1\) 的情况,我们可以单独再维护一个多项式。

Code

【模板】分治 FFT 为例。

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

#define Int register int
#define mod 998244353
#define MAXN 100005

template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

#define poly vector<int>
#define SZ(A) ((A).size())
#define MAXX 600005

int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}

void putout (poly A){
	cout << SZ(A) << ": ";
	for (Int i = 0;i < SZ(A);++ i) cout << A[i] << " , ";cout << endl;
}

int rev[MAXX],w[MAXX];
void init_ntt (){
	int lim = 1 << 19;
	for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 18);
	int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1;
	for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn);
	for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1];
}

void ntt (poly &a,int type){
#define G 3
#define Gi 332748118
	static int d[MAXX];int lim = a.size();
	for (Int i = 0,z = 19 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i];
	for (Int i = 1;i < lim;i <<= 1)
		for (Int j = 0;j < lim;j += i << 1)
			for (Int k = 0;k < i;++ k){
				int x = mul (w[i + k],d[i + j + k]);
				d[i + j + k] = dec (d[j + k],x),d[j + k] = add (d[j + k],x);
			}
	for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod;
	if (type == -1){
		reverse (a.begin() + 1,a.begin() + lim);
		for (Int i = 0,Inv = qkpow (lim,mod - 2);i < lim;++ i) a[i] = mul (a[i],Inv);
	}
#undef G
#undef Gi 
}

poly operator * (poly A,poly B){
	int lim = 1,l = 0,len = SZ(A) + SZ(B) - 1;
	while (lim < SZ(A) + SZ(B)) lim <<= 1,++ l;
	A.resize (lim),B.resize (lim),ntt (A,1),ntt (B,1);
	for (Int i = 0;i < lim;++ i) A[i] = mul (A[i],B[i]);
	ntt (A,-1),A.resize (len);
	return A;
}

int n,g[MAXN],f[MAXN];

void divide (int r){
	if (r == 0) return f[0] = 1,void ();
	int mid = r >> 1;
	divide (mid);
	poly H1,H2;H1.resize (mid + 1),H2.resize (r + 1);
	for (Int i = 0;i <= mid;++ i) H1[i] = f[i];
	for (Int i = 0;i <= r;++ i) H2[i] = g[i];
	H1 = H1 * H2;
	for (Int i = mid + 1;i <= r;++ i) Add (f[i],H1[i]);
	H1.resize (r - mid + 1),H2.resize (mid + 1);
	for (Int i = mid + 1;i <= r;++ i) H1[i - mid - 1] = f[i];
	for (Int i = 1;i <= mid;++ i) H2[i] = f[i];
	H1 = H1 * H2;
	for (Int i = mid + 1;i <= r;++ i) Add (f[i],H1[i - mid - 1]);
}

signed main(){
	init_ntt (),read (n);
	for (Int i = 1;i < n;++ i) read (g[i]);
	divide (n);
	for (Int i = 0;i < n;++ i) write (f[i]),putchar (' ');putchar ('\n');
	return 0;
}
posted @ 2022-02-13 21:03  Dark_Romance  阅读(61)  评论(0编辑  收藏  举报