zoukankan      html  css  js  c++  java
  • 多项式求逆

    多项式求逆


    (A(x))(\%x^{n}) 意义下的逆元 (B(x))

    首先求出 (A(x))(\%x^{lceil frac{n}{2} ceil}) 意义下的逆元 (C(x)),即 $A(x)C(x)=1 $ ((\%x^{lceil frac{n}{2} ceil}))

    移项得 (A(x)C(x)-1 = 0) ((\%x^{lceil frac{n}{2} ceil}))

    两边平方 (A^{2}(x)C^{2}(x)-2A(x)C(x)+1=0) ((\% x^{n}))

    然后两边同时 ( imes B(x))(A(x)C^{2}(x)-2C(x)+B(x)=0) ((\% x^{n}))

    然后得到 (B(x)=2C(x)-A(x)C^{2}(x)) ((\% x^{n}))

    (B(x)=C(x)(2-A(x)C(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;
    	}
    }
    
    int n;
    
    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 main(){
    	scanf("%d",&n);
    	for(int i=0;i<n;++i)scanf("%lld",&A[i]);
    	
    	DivCon(n);
    	
    	for(int i=0;i<n;++i)printf("%lld ",B[i]);
    	printf("
    ");
    	
    	return 0;
    }
    

    luoguP4721 分治FFT

    已知(f(0)=1)

    (f(i)= sum_{j=0}^{i-1}f(j)g(i-j))

    (f)

    分治FFT的做法

    #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 PolyA[maxn],PolyB[maxn];
    
    int n;
    
    long long f[maxn]={0},g[maxn]={0};
    
    void DivFFT(int l,int r){
    	if(l==r){
    		return;
    	}
    	
    	int mid=(l+r)>>1;
    	DivFFT(l,mid);
    	
    	int p1=0,p2=0,len=0;
    	for(int i=l;i<=mid;++i)PolyA[p1++]=f[i];
    	for(int i=1;i<=r-l;++i)PolyB[p2++]=g[i];
    	for(len=1;len<=(p1+p2-2);len<<=1);
    	for(int i=p1;i<len;++i)PolyA[i]=0;
    	for(int i=p2;i<len;++i)PolyB[i]=0;
    	NTT(PolyA,len,1);
    	NTT(PolyB,len,1);
    	for(int i=0;i<len;++i)PolyA[i]=PolyA[i]*PolyB[i]%mm;
    	NTT(PolyA,len,-1);
    	for(int i=mid+1;i<=r;++i){
    		f[i]=(f[i]+PolyA[p1-2+i-mid])%mm;
    	}
    	
    	DivFFT(mid+1,r);
    }
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<n;++i)scanf("%lld",&g[i]);
    	
    	f[0]=1;
    	DivFFT(0,n-1);
    	
    	for(int i=0;i<n;++i)printf("%lld ",f[i]);
    	printf("
    ");
    	
    	return 0;
    }
    
    

    多项式求逆的做法

    (g(0)=0),则(f(i) =sum_{j=0}^{i} f(j)g(i-j))

    那么 (f*g + 1=f)

    (f(1-g)=1)

    (f= frac{1}{1-g})

    (frac{1}{1-g})(\%x^{n+1})下求逆即可

    #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;
    	}
    }
    
    int n;
    
    long long A[maxn],B[maxn],C[maxn];
    
    void PolyInv(int dg){
    	if(dg==1){
    		B[0]=Ksm(A[0],mm-2);
    		return;
    	}
    	
    	PolyInv((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 main(){
    	scanf("%d",&n);
    	for(int i=1;i<n;++i)scanf("%lld",&A[i]);
    	A[0]=1;
    	for(int i=1;i<n;++i)A[i]=(mm-A[i])%mm;
    	PolyInv(n);
    	
    	for(int i=0;i<n;++i)printf("%lld ",B[i]);
    	printf("
    ");
    	
    	return 0;
    }
    

    (f(n)=sum_{i=1}^{n-1}f(i)f(n-i)) 怎么分治FFT???

  • 相关阅读:
    [Android] UI疑问?
    [Android] Gradle sync failed: Unsupported method: BaseConfig.getApplicationIdSuffix().
    [Android] 使用GSON解析json成Bean
    2016工作总结
    【UE】关于UE的一个真实案例
    我在新蛋系的这八年
    关于在线预览word,excel,ppt,pdf的需求处理方法。
    【点滴积累,厚积薄发】windows schedule task中.exe程序的路径问题等问题总结
    【点滴积累,厚积薄发】windows schedule task的最小时间间隔是多少?
    【点滴积累,厚积薄发】修改hosts,并刷新dns缓存
  • 原文地址:https://www.cnblogs.com/zzyer/p/9199618.html
Copyright © 2011-2022 走看看