多项式进阶操作

看到成爷爷写了一篇就跟风写一篇吧,慢慢更

1.多项式求逆

就是给定多项式\(F(x)\),求一个多项式\(G(x)\)

使得

\[F(x)\times G(x)\equiv 1(mod\ x^n)\]

\(mod\ x^n\)就是只考虑前\(n\)

这是一个基于倍增的算法,就是推一下如何从\(mod\ x^{\frac{n}{2}}\)推到\(mod\ x^n\)

设多项式\(B'(x)\)满足

\[F(x)B'(x)\equiv 1(mod\ x^{\frac{n}{2}})\]

求多项式\(B(x)\)满足

\[F(x)B(x)\equiv 1(mod\ x^{n})\]

后面那个忽略前\(n\)项,所以前\(\frac{n}{2}\)项肯定会满足

\[F(x)B(x)\equiv 1(mod\ x^{\frac{n}{2}})\]

和第一个柿子一减

\[F(B-B')\equiv 0(mod\ x^{\frac{n}{2}})\]

显然\(F\)不可能是\(0\),于是只能是\((B-B')=0\)

于是

\[B-B'\equiv 0 (mod\ x^{\frac{n}{2}})\]

两边平方并且乘上\(F\)

\[F(B-B')^2\equiv 0(mod\ x^n)\]

\[F\times B^2-F\times 2BB'+F\times B'^2\equiv 0(mod\ x^n)\]

别忘了\(F(x)B(x)\equiv 1(mod\ x^{\frac{n}{2}})\)就有

\[B-2B'+FB'^2\equiv 0(mod\ x^n)\]

\[B\equiv 2B'-FB'^2(mod\ x^n)\]

发现这个东西可以倍增来求,就是需要一个\(NTT\)

时间复杂度\(T(n)=T(n/2)+O(nlogn)=O(nlogn)\)

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 300005
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const LL mod=998244353;
const LL g[2]={332748118,3};
int n,rev[maxn],len;
LL a[maxn],b[maxn],C[maxn];
inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1ll) S=S*a%mod;b>>=1ll;a=a*a%mod;}return S;}
inline void NTT(LL *f,int o) {
    for(re int i=0;i<len;i++) if(i<rev[i]) std::swap(f[i],f[rev[i]]);
    for(re int i=2;i<=len;i<<=1) {
        int ln=i>>1;LL og1=quick(g[o],(mod-1)/i);
        for(re int l=0;l<len;l+=i) {
            LL og=1,t;
            for(re int x=l;x<l+ln;x++) {
                t=(og*f[ln+x])%mod;
                f[ln+x]=(f[x]-t+mod)%mod;
                f[x]=(f[x]+t)%mod;
                og=(og*og1)%mod;
            }
        }
    }
    if(o) return;
    LL inv=quick(len,mod-2);
    for(re int i=0;i<len;i++) f[i]=(f[i]*inv)%mod;
}
inline void Inv(int n,LL *A,LL *B) {
    if(n==1) {B[0]=quick(A[0],mod-2);return;}
    Inv((n+1)>>1,A,B);len=1;
    while(len<=n+n-2) len<<=1;
    for(re int i=0;i<n;i++) C[i]=A[i];
    for(re int i=n;i<len;i++) C[i]=0;
    for(re int i=0;i<len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)?len>>1:0);
    NTT(C,1),NTT(B,1);
    for(re int i=0;i<len;i++) B[i]=(2ll*B[i]%mod-C[i]*B[i]%mod*B[i]+mod)%mod,B[i]=(B[i]+mod)%mod;
    NTT(B,0);for(re int i=n;i<len;i++) B[i]=0;
    
} 
int main()
{
    n=read();
    for(re int i=0;i<n;i++) a[i]=read();
    Inv(n,a,b);
    for(re int i=0;i<n;i++) printf("%lld ",b[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/asuldb/p/10543247.html
今日推荐