題解 P10249【【模板】多項式複合函式】

ffffyc發表於2024-03-21

\(\text{Link}\)

力求把最新技術翻譯地人人都能看懂。

推薦先學習:多項式複合逆轉置原理

題意

給出兩個 \(n\) 次多項式 \(F(x),G(x)\),求出 \(H(x)\equiv F(G(x))(\bmod x^{n+1})\)

\(n\le 2\times 10^5\)

思路

我們有:

\[h_i=\sum_{j=0}^nf_j[x^i]G^j(x) \]

那麼這是由 \(f\)\(h\) 的一個線性變化,不妨考慮轉置原理,該問題的轉置為:

\[f_j=\sum_{i=0}^nh_i[x^i]G^j(x) \]

不難發現 \(F(x)=[x^n]\dfrac{H_R(x)}{1-yG(x)}\),其中 \(H_R(x)\) 表示把 \(H(x)\) 係數翻轉得到的多項式。如果 \(H(x)\) 是輸入,\(F(x)\) 是輸出,那麼我們可以直接使用 Bostan-Mori 演算法得到答案,那麼根據轉置原理,我們寫出該演算法的轉置即可。可以配合程式碼理解。

關於 Bostan-Mori 演算法的過程與複雜度證明,可參見多項式複合逆

時間複雜度 \(O(n\log^2n)\)

核心程式碼:

namespace PolyC{
	//...
	#define PolyY vector<Poly>
	inline PolyY operator*(const PolyY &a,const PolyY &b){
		int n=a.size(),m=b.size(),p=a[0].size(),q=b[0].size();
		Poly P,Q;
		P.resize(n*(p+q-1)),Q.resize(m*(p+q-1));
		for(int i=0;i<n;i++)
			for(int j=0;j<p;j++)
				P[i*(p+q-1)+j]=a[i][j];
		for(int i=0;i<m;i++)
			for(int j=0;j<q;j++)
				Q[i*(p+q-1)+j]=b[i][j];
		P=P*Q;
		PolyY F(n+m-1,Poly(p+q-1,0)); 
		for(int i=0;i<n+m-1;i++)
			for(int j=0;j<p+q-1;j++)
				F[i][j]=P[i*(p+q-1)+j]; 
		return F;
	}
}
using namespace PolyC;
namespace MulTT{
	inline Poly MulT(const Poly &a,const Poly &b){
		Poly F=a,G=b;
		int n=a.size(),m=b.size();
		reverse(G.begin(),G.end());
		init(n);
		F.resize(lim),G.resize(lim);
		NTT(F,1),NTT(G,1);
		for(int i=0;i<lim;i++)
			G[i]=1ll*F[i]*G[i]%mod;
		NTT(G,-1);
		for(int i=m-1;i<n;i++)
			F[i-m+1]=G[i];
		F.resize(max(0,n-m+1));
		return F;
	}
	inline PolyY MulT(const PolyY &a,const PolyY &b){
		int n=a.size(),m=b.size(),p=a[0].size(),q=b[0].size();
		Poly P,Q;
		P.resize(n*p),Q.resize(m*p);
		for(int i=0;i<n;i++)
			for(int j=0;j<p;j++)
				P[i*p+j]=a[i][j];
		for(int i=0;i<m;i++)
			for(int j=0;j<q;j++)
				Q[i*p+j]=b[m-1-i][q-1-j];
		init(n*p);
		P.resize(lim),Q.resize(lim);
		NTT(P,1),NTT(Q,1);
		for(int i=0;i<lim;i++)
			P[i]=1ll*P[i]*Q[i]%mod;
		NTT(P,-1);
		PolyY F(n-m+1,Poly(p-q+1,0));
		for(int i=m-1;i<n;i++)
			for(int j=q-1;j<p;j++)
				F[i-m+1][j-q+1]=P[i*p+j]; 
		return F;
	}
}
using namespace MulTT;
inline PolyY BostanMoriT(int n,Poly P,PolyY G){
	if(!n){
		int p=G[0].size();
		P.resize(p*2-1);
		return {MulT(P,Inv(G[0]))};
	}
	if(n+1<G.size()) G.resize(n+1);
	PolyY H=G;
	for(int i=1;i<H.size();i+=2)
		for(int j=0;j<H[i].size();j++)
			H[i][j]=dec(0,H[i][j]);
	G=G*H;
	PolyY A,B;
	for(int i=0;i<G.size();i+=2) B.push_back(G[i]);
	PolyY F=BostanMoriT(n/2,P,B);
	int p=H.size(),q=F[0].size();
	A.resize(p*2);
	for(int i=0,j=0;i<p*2;i++){
		if((i&1)==(n&1)&&j<F.size()) A[i]=F[j++];
		else A[i]=Poly(q,0);
	}
	F=MulT(A,H);
	return F;
}
inline Poly Comp(Poly F,Poly G){
	int n=F.size();
	G.resize(n);
	PolyY Q;
	for(int i=0;i<n;i++)
		Q.push_back({!i,dec(0,G[i])});
	PolyY P=BostanMoriT(n-1,F,Q);
	Poly H(n,0); 
	for(int i=0;i<n;i++)
		H[n-1-i]=P[i][0];
	return H;
}

相關文章