多項式求逆

最近進行了一些多項式方面的學習
多項式求逆其實會的很早
但多項式求逆是重要的前置知識
所以今天就來補寫一下博客
多項式求逆就是給你一個多項式f(x)f(x)
求一個g(x)g(x)使得f(x)×g(x)=1 mod xnf(x)\times g(x) = 1\ mod \ x^n
其中×\times表示卷積
其實也就是多項式乘法
爲什麼要mod xnmod\ x^n
就是因爲你找不到一個g(x)g(x)使得上面的式子真的等於11,除非f(x)f(x)只有常數項
證明的話,其實可以很簡單,g(x)g(x)不可能是00,設最高非00次是xx,而f(x)f(x)的最高非00次是yy,則x+yx+y次一定不是00x+yx+y也不是00,乘積就一定不是11
然後一個多項式可逆常數項必須非00,這也是顯然的。
那我們考慮一個簡單的求逆方法:倍增
假設我們已知多項式a(x)a(x),滿足a(x)×f(x) =1 mod xn2a(x)\times f(x) \ =1 \ mod \ x^{\frac{n}{2}},n是偶數
g(x)×f(x)=1 mod xng(x)\times f(x)= 1\ mod \ x^n
因爲g(x)×f(x)=1 mod xn(x)\times f(x)= 1\ mod \ x^n
所以g(x)×f(x) =1 mod xn2g(x)\times f(x) \ =1 \ mod \ x^{\frac{n}{2}}
所以a(x)=g(x) mod xn2a(x)=g(x) \ mod \ x^{\frac{n}{2}}
a(x)g(x) =0 mod xn2a(x)-g(x) \ =0 \ mod \ x^{\frac{n}{2}}
兩邊同時平方a(x)22a(x)g(x)+g(x)2=0 mod xna(x)^2-2a(x)g(x)+g(x)^2=0 \ mod\ x^n
移項g(x)2=2a(x)g(x)a(x)2 mod xng(x)^2=2a(x)g(x)-a(x)^2\ mod \ x^n
兩邊再同時乘a(x)a(x),就得到g(x)=2a(x)f(x)a(x)2 mod xng(x)=2a(x)-f(x)a(x)^2\ mod \ x^n
這樣就可以通過一兩次卷積得到
時間複雜度的話,可得遞推式T(n)=T(n2)+O(nlog(n))T(n)=T(\frac{n}{2})+O(nlog(n))
實際上就是O(nlog(n))O(nlog(n))
但是常數大約爲FFT等的幾倍
板子:

#include<iostream>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cstdio>
#include<time.h>
#include<vector>
#include<algorithm>
using namespace std;
#define REP(i,x,y) for(ll i=x;i<=y;i++)
#define rep(i,n) REP(i,1,n)
#define rep0(i,n) REP(i,0,n-1)
#define repG(i,x) for(ll i=pos[x];~i;i=e[i].next)
#define ll long long
#define db double
const ll N=1e6+7;
const ll INF=1e9+7;
const ll mod=998244353;
ll f[N],g[N],nw[N],q[N],s1[N],s2[N],s3[N];
ll n;
ll Pow(ll x,ll y){
    ll ans=1,now=x;
    while(y){
        if(y&1)ans=ans*now%mod;
        now=now*now%mod;
        y>>=1;
    }
    return ans;
}
void fft(ll *a,bool d,ll o){
    nw[0]=0;
    for(ll i=1;i<o;i*=2)rep0(j,i)nw[i+j]=nw[j]+o/i/2;
    rep0(i,o)q[i]=a[nw[i]];
    for(ll i=1;i<o;i<<=1){
        ll gn=d?Pow(3,mod-1-(mod-1)/i/2):Pow(3,(mod-1)/i/2);
        for(ll j=0;j<o;j+=i*2){
            ll g=1;
            rep0(k,i){
                ll x=q[j+k],y=q[i+j+k]*g%mod;
                q[j+k]=(x+y)%mod;
                q[i+j+k]=(x-y+mod)%mod;
                g=g*gn%mod;
            }
        }
    }
    if(d){
        ll iv=Pow(o,mod-2);
        rep0(i,o)q[i]=q[i]*iv%mod;
    }
    rep0(i,o)a[i]=q[i];
}
void mul(ll *c,ll *a,ll *b,ll len){
    ll cnt=1;
    while(cnt<=len*2)cnt<<=1;
    REP(i,len,cnt-1)a[i]=b[i]=0;
    fft(a,0,cnt);
    fft(b,0,cnt);
    rep0(i,cnt)c[i]=a[i]*b[i]%mod;
    fft(c,1,cnt);
}
int main(){
    scanf("%lld",&n);
    rep0(i,n)scanf("%lld",&f[i]);
    g[0]=Pow(f[0],mod-2);
    for(ll i=1;i<n;i<<=1){
        rep0(j,i)s1[j]=s2[j]=g[j];
        mul(s3,s1,s2,i);
        rep0(j,i*2)s1[j]=s3[j],s2[j]=f[j];
        mul(s3,s1,s2,i*2);
        rep0(j,i*2)g[j]=(2*g[j]-s3[j]+mod)%mod;
    }
    rep0(i,n)printf("%lld ",g[i]);
    return 0;
}

模板來源:luogu4238

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章