• 多项式除法


    多项式除法

    (参考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),然后两边同时( imes 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))的逆元( imes 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("
    ");
    	
    	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("
    ");
    	
    	return 0;
    }
    

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

  • 相关阅读:
    Springboot注解@Scheduled定时任务的使用
    Springboot整合WebSocket和RabbitMQ实现服务器消息推送
    Springboot集成WebSocket实现消息推送功能
    RabbitMq: 主题交换机的使用(Topic Exchange)
    Rabbitmq: @RabbitListener 和 @RabbitHandler 搭配使用
    RabbitMQ开启 mqtt 协议
    @Import的简单使用
    idea快速生成对应数据库的实体类
    HttpClient封装工具类
    TypeScript基本概念
  • 原文地址:https://www.cnblogs.com/zzyer/p/9201004.html
Copyright © 2020-2023  润新知