多项式求逆与多项式除法/取模

多项式求逆

Procedure

多项式求逆是多项式模块中的一个重要操作(“操作”这个词看出如今多项式题是多么的工业化,犹如毒瘤8操作LCT),在做生成函数/多项式除法、多项式取模/多项式多点求值等中均有应用

对于一个n次多项式 F ( x ) F(x) F(x),我们希望求出一个m-1次多项式 G ( x ) G(x) G(x),满足 F ( x ) G ( x ) ≡ 1 ( m o d x m ) F(x)G(x)\equiv 1\pmod {x^m} F(x)G(x)1(modxm)
也就是说, G ( x ) G(x) G(x) F ( x ) F(x) F(x)在模 x m x^m xm意义下的逆(即 x m x^m xm以后的项我们都不管了,前面的项乘起来只有常数项系数为1,其他系数都是0)

多项式求逆运用了倍增的思想
假设我们已经求出了 B ( x ) , B ( x ) F ( x ) ≡ 1 ( m o d x m 2 ) B(x),B(x)F(x)\equiv 1\pmod {x^{m\over 2}} B(x),B(x)F(x)1(modx2m)
考虑如何求 G ( x ) G(x) G(x)

移项
B ( x ) F ( x ) − 1 ≡ 0 ( m o d x m 2 ) B(x)F(x)-1\equiv 0\pmod {x^{m\over 2}} B(x)F(x)10(modx2m)
此时意味着 B ( x ) F ( x ) − 1 B(x)F(x)-1 B(x)F(x)1的0 ~ m/2-1次项的系数全都是0,那么将同余式两边平方,就变成0 ~ m-1次项的系数都为0
因此
( B ( x ) F ( x ) − 1 ) 2 ≡ 0 ( m o d x m ) \left(B(x)F(x)-1\right)^2\equiv 0 \pmod {x^m} (B(x)F(x)1)20(modxm)
展开
F 2 ( x ) B 2 ( x ) − 2 F ( x ) B ( x ) + 1 ≡ 0 ( m o d x m ) F^2(x)B^2(x)-2F(x)B(x)+1\equiv 0\pmod {x^m} F2(x)B2(x)2F(x)B(x)+10(modxm)
提一个 F ( x ) F(x) F(x)出来
F ( x ) ( F ( x ) B 2 ( x ) − 2 B ( x ) ) ≡ − 1 ( m o d x m ) F(x)\left(F(x)B^2(x)-2B(x)\right)\equiv -1\pmod {x^m} F(x)(F(x)B2(x)2B(x))1(modxm)

此时容易看出 G ( x ) ≡ 2 B ( x ) − F ( x ) B 2 ( x ) ( m o d x m ) G(x)\equiv 2B(x)-F(x)B^2(x) \pmod {x^m} G(x)2B(x)F(x)B2(x)(modxm)
这样就求出了 F ( x ) F(x) F(x) x m x^m xm意义下的乘法逆元
我们从m=1开始做,此时直接求常数项的乘法逆元即可,
然后可以推出m=2,4,8,16…
这样一直倍增下去,直到m>=我们所需要的次数,此时直接取前面我们需要的项,后面多出来的直接设为0即可(模掉了没有影响)

注意,由于我们求 G ( x ) G(x) G(x)是在模 x m x^m xm意义下进行的,而不是 x m 2 x^{m\over 2} x2m,因此即使 B ( x ) B(x) B(x)的次数为m/2-1,此时的 F ( x ) F(x) F(x)的次数仍然要取m-1

分析时间复杂度
T ( n ) = T ( n / 2 ) + O ( n log ⁡ n ) = O ( n log ⁡ n ) T(n)=T(n/2)+O(n\log n)=O(n\log n) T(n)=T(n/2)+O(nlogn)=O(nlogn)(常数相当大)

Code

void make(int l,LL *a,LL *b)//l为我们需要的次数,a为待求逆多项式,用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++)
	//由于乘法有平方操作,因此NTT的范围需要开到2倍。
	//t为当前的模数次数,m=t/2
	{
		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 ) F(x) F(x),m次多项式 G ( x ) G(x) G(x)(n>=m),我们希望求出一个n-m次多项式 H ( x ) H(x) H(x),一个至多m-1次的多项式 R ( x ) R(x) R(x),满足 F ( x ) = G ( x ) H ( x ) + R ( x ) F(x)=G(x)H(x)+R(x) F(x)=G(x)H(x)+R(x),并且 R ( x ) R(x) R(x)小于 G ( x ) G(x) G(x)

R ( x ) ≡ 0 ( m o d x n − m + 1 ) R(x)\equiv 0\pmod {x^{n-m+1}} R(x)0(modxnm+1)时,我们就可以直接对 G ( x ) G(x) G(x)求逆了
接下来的方法就比较高妙了:

我们引入多项式的反转操作,即将多项式的系数倒转过来
形式化的,对于n次多项式 F ( x ) F(x) F(x),反转之后就是 x n F ( 1 x ) x^nF\left({1\over x}\right) xnF(x1)

对于上面的等式反转
x n F ( 1 x ) = x n ( G ( 1 x ) H ( 1 x ) + R ( 1 x ) ) x^nF\left({1\over x}\right)=x^n(G\left({1\over x}\right)H\left({1\over x}\right)+R\left({1\over x}\right)) xnF(x1)=xn(G(x1)H(x1)+R(x1))

此时相当于将x替换成1/x,等式仍然成立
右边分配x^n
x n F ( 1 x ) = x m G ( 1 x ) x n − m H ( 1 x ) + x n R ( 1 x ) x^nF\left({1\over x}\right)=x^mG\left({1\over x}\right)x^{n-m}H\left({1\over x}\right)+x^nR\left({1\over x}\right) xnF(x1)=xmG(x1)xnmH(x1)+xnR(x1)

观察各个多项式指数范围的变化。
F ( x ) F(x) F(x)原本的指数范围为 [ 0 , n ] [0,n] [0,n],现在仍然是 [ 0 , n ] [0,n] [0,n]
G ( x ) G(x) G(x)原本的指数范围为 [ 0 , m ] [0,m] [0,m],现在仍然是 [ 0 , m ] [0,m] [0,m]
H ( x ) H(x) H(x)原本的指数范围为 [ 0 , n − m ] [0,n-m] [0,nm],现在仍然是 [ 0 , n − m ] [0,n-m] [0,nm]
但余式有变化:
R ( x ) R(x) R(x)原本的指数范围为 [ 0 , m − 1 ] [0,m-1] [0,m1],现在变成了 [ n − m + 1 , n ] [n-m+1,n] [nm+1,n]

这下好了,如果我们对于等式两边同时模一个 x n − m + 1 x^{n-m+1} xnm+1
F ( x ) , G ( x ) F(x),G(x) F(x),G(x)保留次数小于等于n-m的项, H ( x ) H(x) H(x)不变, R ( x ) R(x) R(x)没了!

x n F ( 1 x ) ≡ x m G ( 1 x ) x n − m H ( 1 x ) ( m o d x n − m + 1 ) x^nF\left({1\over x}\right)\equiv x^mG\left({1\over x}\right)x^{n-m}H\left({1\over x}\right)\pmod {x^{n-m+1}} xnF(x1)xmG(x1)xnmH(x1)(modxnm+1)

此时只需要对于 G ( 1 / x ) G(1/x) G(1/x)求出模意义下的逆,乘一下就得到 H ( 1 / x ) H(1/x) H(1/x),反转回来就是 H ( x ) H(x) H(x)

H ( x ) H(x) H(x)带回原来的式子,一减就可以得出 R ( x ) R(x) R(x)

分析时间复杂度
NTT、多项式求逆的复杂度均为 O ( n log ⁡ n ) O(n\log n) O(nlogn)
因此总的复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)
常数更大了…

Code

void rev(int num,LL *a,LL *b)//反转操作
{
    fo(i,0,num-1) b[i]=a[num-i-1];
}
void div(LL *a,LL *b,LL *d,LL *r)
{
    rev(m+1,b,r);
    make(n-m+1,r,d);//求出除数的逆
    int num=cf[l2[n]]*2;
    prp(num);
    fo(i,0,n) f[i]=a[n-i];
    fo(i,n-m+1,num-1) f[i]=0,d[i]=0;
    NTT(f,0,num),NTT(d,0,num);
    fo(i,0,num-1) d[i]=d[i]*f[i]%mo;
    NTT(d,1,num);
    fo(i,n-m+1,num-1) d[i]=0;
    fo(i,0,(n-m)>>1) swap(d[i],d[n-m-i]);//反转回来,得到商
    fo(i,0,num-1) r[i]=d[i],f[i]=b[i];
    num=cf[l2[n+1]];
    prp(num);
    NTT(f,0,num),NTT(r,0,num);
    fo(i,0,num-1) r[i]=r[i]*f[i]%mo;
    NTT(r,1,num);
    fo(i,0,num-1) r[i]=(a[i]-r[i]+mo)%mo;//得到余式
}
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值