多项式求逆
Procedure
多项式求逆是多项式模块中的一个重要操作(“操作”这个词看出如今多项式题是多么的工业化,犹如毒瘤8操作LCT),在做生成函数/多项式除法、多项式取模/多项式多点求值等中均有应用
对于一个n次多项式
F(x),我们希望求出一个m-1次多项式
G(x),满足
F(x)G(x)≡1(modxm)
也就是说,
G(x)为
F(x)在模
xm意义下的逆(即
xm以后的项我们都不管了,前面的项乘起来只有常数项系数为1,其他系数都是0)
多项式求逆运用了倍增的思想
假设我们已经求出了
B(x),B(x)F(x)≡1(modx2m)
考虑如何求
G(x)
移项
B(x)F(x)−1≡0(modx2m)
此时意味着
B(x)F(x)−1的0 ~ m/2-1次项的系数全都是0,那么将同余式两边平方,就变成0 ~ m-1次项的系数都为0
因此
(B(x)F(x)−1)2≡0(modxm)
展开
F2(x)B2(x)−2F(x)B(x)+1≡0(modxm)
提一个
F(x)出来
F(x)(F(x)B2(x)−2B(x))≡−1(modxm)
此时容易看出
G(x)≡2B(x)−F(x)B2(x)(modxm)
这样就求出了
F(x)模
xm意义下的乘法逆元
我们从m=1开始做,此时直接求常数项的乘法逆元即可,
然后可以推出m=2,4,8,16…
这样一直倍增下去,直到m>=我们所需要的次数,此时直接取前面我们需要的项,后面多出来的直接设为0即可(模掉了没有影响)
注意,由于我们求
G(x)是在模
xm意义下进行的,而不是
x2m,因此即使
B(x)的次数为m/2-1,此时的
F(x)的次数仍然要取m-1
分析时间复杂度
T(n)=T(n/2)+O(nlogn)=O(nlogn)(常数相当大)
Code
void make(int l,LL *a,LL *b)
{
b[0]=ksm(a[0],mo-2);
for(int m=1,t=2,num=4,cnt=2;m<l;m=t,t=num,num<<=1,cnt++)
{
prp(num,cnt);
fo(i,0,m-1) c[i]=a[i],d[i]=b[i];
fo(i,m,t-1) c[i]=a[i];
fo(i,t,num-1) c[i]=0;
NTT(c,0,num),NTT(b,0,num);
fo(i,0,num-1) b[i]=b[i]*b[i]%mo*c[i]%mo;
NTT(b,1,num);
fo(i,0,t-1) b[i]=((LL)2*d[i]-b[i]+mo)%mo;
fo(i,t,num-1) b[i]=0;
}
}
多项式除法(多项式取模)
Procedure
多项式除法/取模也是多项式模块中的一个重要操作,在做生成函数/多项式多点求值等中均有应用。。。
对于一个n次多项式
F(x),m次多项式
G(x)(n>=m),我们希望求出一个n-m次多项式
H(x),一个至多m-1次的多项式
R(x),满足
F(x)=G(x)H(x)+R(x),并且
R(x)小于
G(x)
当
R(x)≡0(modxn−m+1)时,我们就可以直接对
G(x)求逆了
接下来的方法就比较高妙了:
我们引入多项式的反转操作,即将多项式的系数倒转过来
形式化的,对于n次多项式
F(x),反转之后就是
xnF(x1)
对于上面的等式反转
xnF(x1)=xn(G(x1)H(x1)+R(x1))
此时相当于将x替换成1/x,等式仍然成立
右边分配x^n