【模板】多项式求逆

版权声明:欢迎转载(标记出处),写得差还请多指教 https://blog.csdn.net/quan_tum/article/details/82085003

多项式的这些东西我都是从这位大佬的博客中学会的…确实写得很好
多项式求逆元我用了大佬的 O ( n log n ) 的倍增算法

A ( x ) B ( x ) 1 ( mod x x 2 )

A ( x ) A 1 ( x ) 1 ( mod x x 2 )

合并,

A ( x ) ( B ( x ) A 1 ( x ) ) 0 ( mod x x 2 )

因为 A ( x ) 不为零,

( B ( x ) A 1 ( x ) ) 0 ( mod x x 2 )

平方,

B ( x ) 2 + A 2 ( x ) 2 B ( x ) A 1 ( x ) 0 ( mod x )

同乘 A ( x )

B ( x ) 2 A ( x ) + A 1 ( x ) 2 B ( x ) 0 ( mod x )

移项,

A 1 ( x ) B ( x ) ( 2 B ( x ) × A ( x ) ) ( mod x )

再用NTT解决

#include<bits/stdc++.h>
#define il inline
#define swap(x,y) (x^=y,y^=x,x^=y)
#define p(a,b) 1ll*a*b%mo
#define add(a,b) (a+b>=mo?a+b-mo:a+b)
#define dec(a,b) (a-b<0?a-b+mo:a-b)
using namespace std;
const int N=(1<<21)+5,mo=998244353,G=3,Gi=332748118;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
il int read(){
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=(x+(x<<2)<<1)+c-48;
    return x*f;
}
char sr[1<<21],z[20];int C=-1,Z;
il void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
il void print(int x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=' ';
}
il int qpow(int a,int k){
    int base=1;
    while(k){
        if(k&1) base=p(a,base);
        a=p(a,a);k>>=1;
    }
    return base%mo;
}
int n,r[N],x[N],y[N],A[N],B[N],Og[N];
il void NTT(int *a,int type,int len){
    int limit=1,L=0;
    while(limit<len) limit<<=1,L++;
    for(int i=0;i<limit;++i) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));   
    for(int i=0;i<limit;++i) if(i<r[i]) swap(a[i],a[r[i]]);
    for(int mid=1;mid<limit;mid<<=1){    
        int  R=mid<<1;
        int  W=qpow(G,(mo-1)/R);Og[0]=1;
        for(int j=1;j<mid;++j) Og[j]=p(Og[j-1],W);
        for(int j=0;j<limit;j+=R){
            for(int k=0;k<mid;++k){
                 const int x=a[j+k],y=p(Og[k],a[j+k+mid]);
                 a[j+k]=add(x,y),a[j+k+mid]=dec(x,y);
            }
        }
    }
    if(type==-1){
        reverse(A+1,A+limit+1);
        for(int i=0,inv=qpow(len,mo-2);i<limit;++i) A[i]=1ll*A[i]*inv%mo;
    }
}
void inv(int *a,int *b,int len){
    if(len==1){
        b[0]=qpow(a[0],mo-2);
        return ;
    }
    inv(a,b,len>>1);
    for(int i=0;i<len;++i) A[i]=a[i],B[i]=b[i];
    NTT(A,1,len<<1);NTT(B,1,len<<1);
    for(int i=0;i<(len<<1);++i) A[i]=p(p(A[i],B[i]),B[i]) ;
    NTT(A,-1,len<<1);
    for(int i=0;i<len;++i) b[i]=(1ll*(b[i]<<1)%mo+mo-A[i])%mo;
}
int main(){
    n=read();
    for(int i=0;i<n;++i) x[i]=(read()+mo)%mo;
    int Len=1;for(;Len<n;Len<<=1);inv(x,y,Len);
    for(int i=0;i<n;++i) print(y[i]);Ot();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/quan_tum/article/details/82085003