html 中的 %3c p%3e,多项式求逆 - osc_f47lo76p的个人空间 - OSCHINA - 中文开源技术交流社区...

多项式求逆

定义

设$\displaystyle f(x) =\sum^{n-1}{k=0}a_kx^k$求$g(x) =\sum^{n-1}{k=0}b_kx^k$,使得 $\displaystyle f(x)g(x)\equiv 1 (\mod x^n)$

即$\displaystyle f(x)g(x)$ 的前$n$项中只有常数项为$1$,其余项均为$0$,称为

求$f(x)$模$\displaystyle x^n$的逆元,或简称求$f(x)$的逆元。

多项式可逆当且仅当其常数项可逆,证明见“方法一”$\displaystyle b_0=\frac{1}{a_0}$

方法1:分治FFT

从常数项出发,比较系数得$\displaystyle b_0=\frac{1}{a_0}$且$\displaystyle \sum^k_{i=0}b_ia_{k-i}=0$那么有 $$b_k=\sum^{k-1}{i=0}b_i(-\frac{a{k-i}}{a_0})$$ 从而可以通过分治FFT 计算,时间复杂度$\displaystyle \Theta(n \log^2 n)$。

方法2:倍增法

考虑倍增,从局部的逆元(低次)出发,设$\displaystyle g_0(x) = g(x) \mod x^k$,那么有 $$f(x)g_0(x)-1\equiv 0 (\mod x^k)$$ 从而有 $$f(x)g_0(x)-1)^2\equiv 0 (mod x^{2k})$$ 可以发现模的次数增加了,此时展开左边可得

$$g(x)\equiv g_0(x)(2-f(x)g_0(x))(\mod x^{2k})$$

从而可以算出$g(x)$的前$2k$项。

通过摊还分析得时间复杂度为$\displaystyle \Theta(n \log n)$

实现

多项式求逆的实现不难,两种方法都可以,但第二种更快,也更容易实现,故此处以方法二为例。 我们每次递归算出模$\displaystyle x^{\frac{n}{2}}$的逆元,记为$g_0$,再套用$\displaystyle g(x)\equiv g_0(x)(2-f(x)g_0(x))(\mod x^{2k})$,用FFT计算即可

void solve(LL *a,LL *b,int p){/*a:seq,b:inv*/

if(p==1){

b[0]=fpm(a[0],MOD-2);

return;

}

solve(a,b,(p+1)>>1);

lim=1; L=0;

while(lim

lim<<=1;

L++;

}

for(int i=0;i

rev[i]=rev[i>>1]>>1|(1&i)<

for(int i=0;i

tmp[i]=a[i];

for(int i=p;i

tmp[i]=0;

NTT(tmp,1); NTT(b,1);

for(int i=0;i

b[i]=(2-b[i]*tmp[i]%MOD+MOD)%MOD*b[i]%MOD;

NTT(b,-1);

for(int i=p;i

b[i]=0;

}

例题

[P4238 【模板】多项式求逆](%3Ca href="https://www.luogu.org/problem/P4238"%3Ehttps://www.luogu.org/problem/P4238%3C/a%3E)

这是纯粹的模板题,直接给代码

#include

using namespace std;

typedef long long LL;

const int INF=1e9+7,MAXN=3e6+10/*Min:2^20+10*/;

const LL G=3,MOD=998244353,INV=332748118;

inline LL fpm(LL base,LL p){

LL ret=1;

while(p){

if(p&1)

ret=ret*base%MOD;

base=base*base%MOD;

p>>=1;

}

return ret%MOD;

}

int N,M,lim=1,L,rev[MAXN];

inline void NTT(LL *a,int type){

for(int i=0;i

if(i

swap(a[i],a[rev[i]]);

for(int mid=1;mid

int len=mid<<1/*n*/;

LL Wn=fpm(G,(MOD-1)/len);

for(int j=0;j

LL w=1,t1,t2;

for(int k=0;k

t1=a[j+k],t2=w*a[j+k+mid]%MOD;

a[j+k]=(t1+t2)%MOD;

a[j+k+mid]=(t1-t2+MOD)%MOD;

w=w*Wn%MOD;

}

}

}

if(type==-1){

LL lim_inv=fpm(lim,MOD-2);

reverse(a+1,a+lim);

for(int i=0;i

a[i]=a[i]*lim_inv%MOD;

}

}

LL tmp[MAXN];

void solve(LL *a,LL *b,int p){/*a:seq,b:inv*/

if(p==1){

b[0]=fpm(a[0],MOD-2);

return;

}

solve(a,b,(p+1)>>1);

lim=1; L=0;

while(lim

lim<<=1;

L++;

}

for(int i=0;i

rev[i]=rev[i>>1]>>1|(1&i)<

for(int i=0;i

tmp[i]=a[i];

for(int i=p;i

tmp[i]=0;

NTT(tmp,1); NTT(b,1);

for(int i=0;i

b[i]=(2-b[i]*tmp[i]%MOD+MOD)%MOD*b[i]%MOD;

NTT(b,-1);

for(int i=p;i

b[i]=0;

}

LL a[MAXN],b[MAXN];

int main(){

scanf("%d",&N);

for(int i=0;i

scanf("%lld",a+i);

a[i]=(a[i]+MOD)%MOD;

}

solve(a,b,N);

for(int i=0;i

printf("%lld ",b[i]);

return 0;

}

[P4239 【模板】多项式求逆(加强版)](%3Ca href="https://www.luogu.org/problem/P4239"%3Ehttps://www.luogu.org/problem/P4239%3C/a%3E)

这道题是在任意模数下的多项式求逆,需要将上一个板子的NTT改成MTT

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值