多项式求逆
多项式求逆元
已知一度数为n的多项式\(A(x)\)。
\[A(x)B(x)\equiv1\pmod {x^n}
\]
\(B(x)\)即为\(A(x)\)的逆元。
多项式的除法、\(\exp\)和\(\ln\)都是基于多项式求逆的。
通常用倍增法处理多项式求逆问题。
开始推式子……
\[\begin{aligned}
&AB'\equiv1\pmod {x^{\lceil\frac n 2\rceil}}\\
&A(B-B’)\equiv 0 \pmod {x^{\lceil\frac n 2\rceil}}\\
&B-B’\equiv 0 \pmod {x^{\lceil\frac n 2\rceil}}\\
&(B-B’)^2\equiv 0 \pmod {x^n}\\
&B^2+B'^2-2BB'\equiv 0 \pmod {x^n}\\
&A(B^2+B'^2-2BB')\equiv 0 \pmod {x^n}\\
&B-2B'+AB'^2\equiv 0 \pmod {x^n}\\
&B\equiv 2B'-AB'^2\pmod {x^n}\\
&B\equiv B'(2-AB')\pmod {x^n}\\
\end{aligned}
\]
这样我们可以从\(x^n\)递归到\(x^0\)。
使用NTT加速运算,复杂度\(O(n \log n)\)。
ll qp(ll d,ll c)
{
ll res=1;
while(c)
{
if(c&1) res=d*res%mod;
d=d*d%mod,c>>=1;
}
return res;
}
void ntt(ll *a,int type)
{
for(int i=0;i<lim;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int mid=1;mid<lim;mid<<=1)
{
ll wn=qp(type?g:gi,(mod-1)/(mid<<1));
for(int i=0;i<lim;i+=(mid<<1))
{
ll w=1;
for(int j=0;j<mid;j++,w=w*wn%mod)
{
ll x=a[i+j],y=w*a[i+j+mid]%mod;
a[i+j]=(x+y)%mod;
a[i+j+mid]=(x-y+mod)%mod;
}
}
}
if(!type)
{
ll inv=qp(lim,mod-2);
for(int i=0;i<lim;i++)
a[i]=(a[i]*inv)%mod;
}
}
void qn(ll deg,ll *a,ll *b)
{
if(deg==1)
{
b[0]=qp(a[0],mod-2);
return;
}
qn((deg+1)/2,a,b);
bit=0,lim=1;
for(;lim<deg*2;lim*=2)
bit++;
for(int i=1;i<lim;i++)
rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
for(int i=0;i<deg;i++)
c[i]=a[i];
for(int i=deg;i<lim;i++)
c[i]=0;
ntt(c,1),ntt(b,1);
for(int i=0;i<lim;i++)
b[i]=(2-c[i]*b[i]%mod+mod)%mod*b[i]%mod;
ntt(b,0);
for(int i=deg;i<lim;i++)
b[i]=0;
}