【模板】多项式求逆

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

A(x)B(x)1(modxx2) A ( x ) B ( x ) ≡ 1 ( mod x ⌈ x 2 ⌉ )

A(x)A1(x)1(modxx2) A ( x ) A − 1 ( x ) ≡ 1 ( mod x ⌈ x 2 ⌉ )

合并,

A(x)(B(x)A1(x))0(modxx2) A ( x ) ( B ( x ) − A − 1 ( x ) ) ≡ 0 ( mod x ⌈ x 2 ⌉ )

因为 A(x) A ( x ) 不为零,

(B(x)A1(x))0(modxx2) ( B ( x ) − A − 1 ( x ) ) ≡ 0 ( mod x ⌈ x 2 ⌉ )

平方,

B(x)2+A2(x)2B(x)A1(x)0(modx) B ( x ) 2 + A − 2 ( x ) − 2 B ( x ) A − 1 ( x ) ≡ 0 ( mod x )

同乘 A(x) A ( x )

B(x)2A(x)+A1(x)2B(x)0(modx) B ( x ) 2 A ( x ) + A − 1 ( x ) − 2 B ( x ) ≡ 0 ( mod x )

移项,

A1(x)B(x)(2B(x)×A(x))(modx) 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值