多项式除法

多项式除法

(参考Miskcoo's Space)


\(n\)次多项式 A(x),\(m\)次多项式 B(x),要求出两个多项式 \(D(x)\)\(R(x)\),满足

\(A(x)=D(x)B(x)+R(x)\)

并且\(degD<=n-m,deg<m\)

定义 \(A^{R}(x)=x^{n}A(\frac{1}{x})\),也就是把\(A(x)\)的系数翻转

对于式子 \(A(x)=D(x)B(x)+R(x)\),我们用\(\frac{1}{x}\)替换掉\(x\),然后两边同时\(\times x^{n}\),得到

\(x^{n}A(\frac{1}{x})=x^{n-m}D(\frac{1}{x})x^{m}B(\frac{1}{x})+x^{n-m+1}x^{m-1}R(\frac{1}{x})\)

\(A^{R}(x)=D^{R}(x)B^{R}(x)+x^{n-m+1}R^{R}(x)\)

\(D^{R}(x)\)的最高次数是\(n-m\)\(x^{n-m+1}R^{R}(x)\)的最低次数是\(n-m+1\)

所以我们把上面的的式子放到 \(\% x^{n-m+1}\) 意义下,\(R(x)\)的影响就被消除了

所以现在式子变成了\(A^{R}(x)=D^{R}(x)B^{R}(x)\) \((\% x^{n-m+1})\)

\(B^{R}(x)\)的逆元\(\times A^{R}(x)\)得到\(D^{R}(x)\)

然后翻转过来得到\(D(x)\)\(R(x)=A(x)-D(x)B(x)\),就都求出来了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=400009;

const int mm=998244353;

long long Ksm(long long a,int p){
	long long ret=1;
	for(;p;p>>=1,a=a*a%mm){
		if(p&1)ret=ret*a%mm;
	}
	return ret;
}

int rev[maxn];
void NTT(long long *arr,int n,int f){
	int b=0;
	for(int len=1;len<n;len<<=1)++b;
	for(int i=0;i<n;++i)rev[i]=(rev[i>>1]>>1)|((i&1)<<(b-1));
	for(int i=0;i<n;++i)if(i<rev[i])swap(arr[i],arr[rev[i]]);
	
	for(int k=1;k<n;k<<=1){
		int p=k+k;
		long long wn=Ksm(3LL,(mm-1)/p);
		if(f==-1)wn=Ksm(wn,mm-2);
		
		for(int i=0;i<n;i+=p){
			long long w=1;
			for(int j=0;j<k;++j,w=w*wn%mm){
				long long x=arr[i+j],y=arr[i+j+k]*w%mm;
				arr[i+j]=(x+y)%mm;
				arr[i+j+k]=(x-y+mm)%mm;
			}
		}
	}
	
	if(f==-1){
		long long inv=Ksm(n*1LL,mm-2);
		for(int i=0;i<n;++i)arr[i]=arr[i]*inv%mm;
	}
}

long long A[maxn],B[maxn],C[maxn];

void DivCon(int dg){
	if(dg==1){
		B[0]=Ksm(A[0],mm-2);
		return;
	}
	
	DivCon((dg+1)>>1);
	
	int len=1;
	for(len=1;len<(dg<<1);len<<=1);
	
	for(int i=0;i<dg;++i)C[i]=A[i];
	for(int i=dg;i<len;++i)C[i]=0;
	NTT(B,len,1);
	NTT(C,len,1);
	for(int i=0;i<len;++i)B[i]=B[i]*(2-B[i]*C[i]%mm+mm)%mm;
	
	NTT(B,len,-1);
	
	for(int i=dg;i<len;++i)B[i]=0;
}

int n,m;
long long F[maxn],G[maxn];
long long Q[maxn],R[maxn];

long long D[maxn];

int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;++i)scanf("%lld",&F[i]);
	for(int i=0;i<=m;++i)scanf("%lld",&G[i]);
	
	int len=0;
	for(len=1;len<=(n-m+1)*2;len<<=1);
	
	for(int i=0;i<=m;++i)A[i]=G[m-i];
	DivCon(n-m+1);
	for(int i=0;i<n-m+1;++i)D[i]=F[n-i];
	
	
	NTT(B,len,1);
	NTT(D,len,1);
	for(int i=0;i<len;++i)D[i]=B[i]*D[i]%mm;
	NTT(D,len,-1);
	
	for(int i=0;i<=n-m;++i)Q[i]=D[n-m-i];
	for(int i=0;i<=n-m;++i)printf("%lld ",Q[i]);
	printf("\n");
	
	memset(D,0,sizeof(D));
	for(len=1;len<=n;len<<=1);
	NTT(G,len,1);
	NTT(Q,len,1);
	for(int i=0;i<len;++i)D[i]=G[i]*Q[i]%mm;
	NTT(D,len,-1);
	for(int i=0;i<m;++i)R[i]=(F[i]-D[i]+mm)%mm;
	
	
	for(int i=0;i<m;++i)printf("%lld ",R[i]);
	printf("\n");
	
	return 0;
}

坑:不知道为什么一定存在这样的Q(x)和R(x)

posted @ 2018-06-19 20:44  ws_zzy  阅读(522)  评论(0编辑  收藏  举报