最近進行了一些多項式方面的學習
多項式求逆其實會的很早
但多項式求逆是重要的前置知識
所以今天就來補寫一下博客
多項式求逆就是給你一個多項式
求一個使得
其中表示卷積
其實也就是多項式乘法
爲什麼要呢
就是因爲你找不到一個使得上面的式子真的等於,除非只有常數項
證明的話,其實可以很簡單,不可能是,設最高非次是,而的最高非次是,則次一定不是,也不是,乘積就一定不是
然後一個多項式可逆常數項必須非,這也是顯然的。
那我們考慮一個簡單的求逆方法:倍增
假設我們已知多項式,滿足,n是偶數
求
因爲g
所以
所以
則
兩邊同時平方
移項
兩邊再同時乘,就得到
這樣就可以通過一兩次卷積得到
時間複雜度的話,可得遞推式
實際上就是
但是常數大約爲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