多项式除法&取模

除法&取模

n n n 次多项式 F ( x ) F(x) F(x) m m m 次多项式 G ( x ) G(x) G(x) ,求 n − m n-m nm 次多项式 Q ( x ) Q(x) Q(x) m − 1 m-1 m1 次多项式 R ( x ) R(x) R(x) 满足 F ( x ) = G ( x ) Q ( x ) + R ( x ) F(x)=G(x)Q(x)+R(x) F(x)=G(x)Q(x)+R(x)
于是我们有 F ( 1 x ) = G ( 1 x ) Q ( 1 x ) + R ( 1 x ) F(\frac{1}{x})=G(\frac{1}{x})Q(\frac{1}{x})+R(\frac{1}{x}) F(x1)=G(x1)Q(x1)+R(x1)
两遍同乘 x n x^n xn x n F ( 1 x ) = x m G ( 1 x ) x n − m Q ( 1 x ) + x n − m + 1 x m − 1 R ( 1 x ) x^nF(\frac{1}{x})=x^mG(\frac{1}{x})x^{n-m}Q(\frac{1}{x})+x^{n-m+1}x^{m-1}R(\frac{1}{x}) xnF(x1)=xmG(x1)xnmQ(x1)+xnm+1xm1R(x1)
对于 n n n 次多项式 A ( x ) A(x) A(x) x n A ( 1 x ) x^nA(\frac{1}{x}) xnA(x1) 代表的是多项式系数对称交换,设其为 a ( x ) a(x) a(x),则 f ( x ) = g ( x ) q ( x ) + x n − m + 1 r ( x ) f(x)=g(x)q(x)+x^{n-m+1}r(x) f(x)=g(x)q(x)+xnm+1r(x)
由于 Q ( x ) Q(x) Q(x) n − m n-m nm 次多项式,于是式子满足 f ( x ) ≡ g ( x ) q ( x ) ( m o d x n − m + 1 ) f(x)\equiv g(x)q(x) \pmod{x^{n-m+1}} f(x)g(x)q(x)(modxnm+1)
于是 q ( x ) ≡ f ( x ) g ( x ) ( m o d x n − m + 1 ) q(x)\equiv \frac{f(x)}{g(x)} \pmod{x^{n-m+1}} q(x)g(x)f(x)(modxnm+1)
多项式求逆即可
于是我们可以求出 Q ( x ) Q(x) Q(x) ,根据定义求出 R ( x ) R(x) R(x) 即可

代码
#include <bits/stdc++.h>
using namespace std;
const int N=6e5+5,P=998244353;
int n,m,f[N],g[N],G[2]={3,(P+1)/3},A[N],B[N],t,p,re[N],d[N],q[N];
int X(int x){return x>=P?x-P:x;}
int K(int x,int y){
	int z=1;
	for (;y;y>>=1,x=1ll*x*x%P)
		if (y&1) z=1ll*z*x%P;
	return z;
}
void put(int *a,int l){
	for (int i=0;i<=l;i++)
		printf("%d",a[i]),
		putchar(i<l?' ':'\n');
}
void pre(int l){
	for (t=1,p=0;t<l;t<<=1,p++);
	for (int i=0;i<t;i++)
		re[i]=(re[i>>1]>>1)|((i&1)<<(p-1));
}
void Ntt(int *a,int o){
	for (int i=0;i<t;i++)
		if (i<re[i]) swap(a[i],a[re[i]]);
	for (int wn,i=1;i<t;i<<=1){
		wn=K(G[o],(P-1)/(i<<1));
		for (int x,y,j=0;j<t;j+=(i<<1))
			for (int w=1,k=0;k<i;k++,w=1ll*w*wn%P)
				x=a[j+k],y=1ll*w*a[i+j+k]%P,
				a[j+k]=X(x+y),a[i+j+k]=X(x-y+P);
	}
	if (o)
		for (int i=0,v=K(t,P-2);i<t;i++)
			a[i]=1ll*a[i]*v%P;
}
void inv(int *a,int *b,int l){
	if (l==1){
		b[0]=K(a[0],P-2);
		return;
	}
	inv(a,b,(l+1)>>1);
	for (int i=0;i<l;i++)
		A[i]=a[i],B[i]=b[i];
	pre(l<<1);Ntt(A,0);Ntt(B,0);
	for (int i=0;i<t;i++)
		A[i]=1ll*A[i]*B[i]%P*B[i]%P;
	Ntt(A,1);
	for (int i=0;i<l;i++)
		b[i]=X(X(b[i]<<1)+P-A[i]);
	for (int i=0;i<t;i++) A[i]=B[i]=0;
}
void dvs(int *f,int *g,int *q,int *d){
	reverse(f,f+n+1);reverse(g,g+m+1);
	inv(g,q,n-m+1);
	for (int i=0;i<=n-m;i++)
		A[i]=q[i],B[i]=f[i];
	pre((n-m+1)<<1);Ntt(A,0);Ntt(B,0);
	for (int i=0;i<t;i++)
		A[i]=1ll*A[i]*B[i]%P;
	Ntt(A,1);
	for (int i=0;i<=n-m;i++) q[i]=A[i];
	for (int i=0;i<t;i++) A[i]=B[i]=0;
	reverse(q,q+n-m+1);
	reverse(f,f+n+1);reverse(g,g+m+1);
	for (int i=0;i<=m;i++) A[i]=g[i];
	for (int i=0;i<=n-m;i++) B[i]=q[i];
	pre(n+2);Ntt(A,0);Ntt(B,0);
	for (int i=0;i<t;i++)
		A[i]=1ll*A[i]*B[i]%P;
	Ntt(A,1);
	for (int i=0;i<m;i++)
		d[i]=X(f[i]-A[i]+P);
	for (int i=0;i<t;i++) A[i]=B[i]=0;
}
int main(){
	cin>>n>>m;
	for (int i=0;i<=n;i++)
		scanf("%d",&f[i]);
	for (int i=0;i<=m;i++)
		scanf("%d",&g[i]);
	dvs(f,g,q,d);
	put(q,n-m);put(d,m-1);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值