1. 程式人生 > 實用技巧 >【洛谷4512】【模板】多項式除法

【洛谷4512】【模板】多項式除法

點此看題面

大致題意: 給定多項式\(F(x),G(x)\),求\(Q(x),R(x)\)滿足\(F(x)=Q(x)*G(x)+R(x)\)

前言

公式的推導看起來十分自然,然而遠不是我這種蒟蒻所能想到的。

推式子

定義\(F_R(x)\)表示將\(F(x)\)係數翻轉得到的式子(即\(F_R(x)[i]=F(x)[n-i]\)),顯然有:

\[F_R(x)=x^n*F(\frac1x) \]

然後對於原式我們進行轉化:

\[F(x)=Q(x)*G(x)+R(x) \]

\[F(\frac1x)=Q(\frac1x)*G(\frac1x)+R(\frac1x) \]

\[x^n*F(\frac1x)=(x^{n-m}*Q(\frac1x))*(x^m*G(\frac1x))+x^{n-m+1}*(x^{m-1}*R(\frac1x)) \]

\[F_R(x)=Q_R(x)*G_R(x)+x^{n-m+1}*R_R(x) \]

我們把這個式子兩邊同時向\(x^{n-m+1}\)取模,這樣就可以消去\(R_R(x)\)這一項,同時依然能保留\(Q_R(x)\)的有效係數,得到:

\[F_R(x)\equiv Q_R(x)*G_R(x)(mod\ x^{n-m+1}) \]

\[Q_R(x)\equiv F_R(x)*G_R^{-1}(x)(mod\ x^{n-m+1}) \]

於是只要通過多項式乘法逆就能求出\(Q(x)\)了,而\(R(x)\)的計算是很簡單的:

\[R(x)=F(x)-Q(x)*G(x) \]

程式碼

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define X 998244353
using namespace std;
int n,m,f[N+5],g[N+5],q[N+5],r[N+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
#define QI(x) QP(x,X-2)
namespace Poly
{
	#define Init(n) P=1,L=0;W(P<=2*(n)) P<<=1,++L;\
		for(i=0;i^P;++i) A[i]=B[i]=0,R[i]=(R[i>>1]>>1)|((i&1)<<L-1);
	int PR=3,IPR=QI(3),P,L,R[4*N+5],A[4*N+5],B[4*N+5],p[N+5];
	I void NTT(int *s,CI t)//NTT
	{
		RI i,j,k,x,y,U,S;for(i=0;i^P;++i) i<R[i]&&(x=s[i],s[i]=s[R[i]],s[R[i]]=x);
		for(i=1;i^P;i<<=1) for(U=QP(t,(X-1)/(i<<1)),j=0;j^P;j+=i<<1) for(S=1,k=0;k^i;
			++k,S=1LL*S*U%X) s[j+k]=((x=s[j+k])+(y=1LL*S*s[i+j+k]%X))%X,s[i+j+k]=(x-y+X)%X;
	}
	I void Mul(CI n,int *a,int *b,int *c)//多項式乘法
	{
		RI i;Init(n);for(i=0;i<=n;++i) A[i]=a[i],B[i]=b[i];
		for(NTT(A,PR),NTT(B,PR),i=0;i^P;++i) A[i]=1LL*A[i]*B[i]%X;
		RI t=QI(P);for(NTT(A,IPR),i=0;i<=n;++i) c[i]=1LL*A[i]*t%X;
	}
	I void Inv(CI n,int *a,int *b)//多項式求逆
	{
		if(!n) return (void)(b[0]=QI(a[0]));RI i;Inv(n>>1,a,b);
		Init(n);for(i=0;i<=n;++i) A[i]=a[i],B[i]=b[i];
		for(NTT(A,PR),NTT(B,PR),i=0;i^P;++i) B[i]=(2LL*B[i]-1LL*A[i]*B[i]%X*B[i]%X+X)%X;
		RI t=QI(P);for(NTT(B,IPR),i=0;i<=n;++i) b[i]=1LL*B[i]*t%X;
	}
	I void Rev(CI n,int *a)//翻轉系數
	{
		RI i;for(i=0;i<=n;++i) A[i]=a[n-i];for(i=0;i<=n;++i) a[i]=A[i];
	}
	I void Div(int *f,int *g,int *q,int *r)//多項式除法
	{
		RI i;Rev(n,f),Rev(m,g),Inv(n-m,g,p),Mul(n-m,f,p,q);Rev(n-m,q);//通過多項式求逆得到q
		Rev(n,f),Rev(m,g),Mul(n,g,q,p);for(i=0;i^m;++i) r[i]=(f[i]-p[i]+X)%X;//餘數(r)=被除數(f)-除數(g)×商(q)
	}
}
int main()
{
	RI i;for(F.read(n),F.read(m),i=0;i<=n;++i) F.read(f[i]);for(i=0;i<=m;++i) F.read(g[i]);//讀入
	for(Poly::Div(f,g,q,r),i=0;i<=n-m;++i) F.write(q[i]," \n"[i==n-m]);//輸出商
	for(i=0;i^m;++i) F.write(r[i]," \n"[i==m-1]);return F.clear(),0;//輸出餘數
}