常系数齐次递推 / 多项式取模

这个坑开这很久了,一直没机会填。趁着省选前复习的机会赶工。。。。

多项式取模的定义

说到取模,我们大概会想到这个式子:
A ( x ) ÷ B ( x ) = D ( x ) . . . . . R ( x ) A(x)\div B(x)=D(x).....R(x) A(x)÷B(x)=D(x).....R(x)
其中A是被除多项式,B是除多项式,D是A除以B的"商",而R就称作余多项式。
换个更直接的说法:即有 A ( x ) = B ( x ) D ( x ) + R ( x ) A(x)=B(x)D(x)+R(x) A(x)=B(x)D(x)+R(x)

想想整数除法中,余数必须要小于除数。类似的,我们要保证R(x)的次数严格小于B(x)。
也就是,假如 A ( x ) A(x) A(x)的最高次项是 x n x^n xn B ( x ) B(x) B(x)的最高次项是 x m x^m xm
(这里的最高次项指系数不为0的次数最大项。)
那么 D ( x ) D(x) D(x)的最高次项必须为 x n − m x^{n-m} xnm R ( x ) R(x) R(x)的最高次项必须小于 x m x^m xm

考虑一个暴力取模的做法,每次看 A ( x ) A(x) A(x)最高次项是否大于等于 x m x^m xm,如果是,则通过加减 B ( x ) B(x) B(x)或其倍数消去这一项。直到不能再进行这个操作,我们便得到了余多项式。由此,对于A除以B来说,余多项式是唯一的,商也是唯一的。

快速做多项式取模

A ( x ) = B ( x ) D ( x ) + R ( x ) A(x)=B(x)D(x)+R(x) A(x)=B(x)D(x)+R(x)
观察上式,已知A和B的时候,我们想要求两个未知(但又被A,B唯一确定了的)多项式:D和R。

假如没有R(x),要你求 A ( x ) = B ( x ) D ( x ) A(x)=B(x)D(x) A(x)=B(x)D(x)中的D(x),你会做吗?

答案是多项式求逆的简单应用。对B(x)求逆即可,再将A乘上B的逆,就是D了。

题外话:
当然,假如B不止有常数项的话,B的逆是无穷项的。而我们知道D的最高次项,只需要做这么多的逆就够了。

那么,能不能通过一些手段,消去其中R(x)的影响呢?
当然可以,(不然我写这东西干嘛…)

我们将A(x)的所有系数翻转,使得原本是 x n x^n xn的系数变成常数项,原本是 x n − 1 x^{n-1} xn1的系数变成一次项系数…
这个操作如何用式子表示呢: x n A ( 1 x ) x^nA(\frac 1 x) xnA(x1)

考虑对置顶的式子左右同时做该变换,等式仍然成立:
x n A ( 1 x ) = x n ( B ( 1 x ) D ( 1 x ) + R ( 1 x ) ) x^nA(\frac 1 x) = x^n(B(\frac 1 x)D(\frac1 x)+R(\frac 1x )) xnA(x1)=xn(B(x1)D(x1)+R(x1))
对于左边,我们已经知道这是在将系数翻转。那对于右边呢?不妨将 x n x^n xn分进去。

x n A ( 1 x ) = x m B ( 1 x ) x n − m D ( 1 x ) + x m − 1 R ( 1 x ) x n − m + 1 x^nA(\frac 1 x) = x^mB(\frac 1 x)x^{n-m}D(\frac1 x)+x^{m-1}R(\frac 1x )x^{n-m+1} xnA(x1)=xmB(x1)xnmD(x1)+xm1R(x1)xnm+1
怎么样,你看出来了吗?
事实上,我们是对A,B,D,R同时做系数翻转(当然,需要假设其最高次项分别是 x n , x m , x n − m , x m − 1 x^n,x^m,x^{n-m},x^{m-1} xn,xm,xnm,xm1)。再将R向高次移动 n − m + 1 n-m+1 nm+1位。

改写一下,
A ′ ( x ) = B ′ ( x ) D ′ ( x ) + R ′ ( x ) x n − m + 1 A'(x)=B'(x)D'(x)+R'(x)x^{n-m+1} A(x)=B(x)D(x)+R(x)xnm+1

好看多了。这时候,让你求D’,你会求吗?

答案很简单,由于 D 和 D ′ D和D' DD的最高次项是 x n − m x^{n-m} xnm,可以直接求 D ′ D' D在模 x n − m + 1 x^{n-m+1} xnm+1意义下的值。然后还原回D,这便是完整的D。

那么我们的最关键问题迎刃而解,剩下的部分就是手到擒来。

关键思想是先系数翻转,再把余多项式用模意义抹去。

常系数齐次线性递推

有了多项式取模,这事实上是个很简单的东西。

这个线性递推中的任意项 g x g_x gx,都可以用 g 1 , g 2 . . . g k g_1,g_2...g_k g1,g2...gk表示出来。
不妨设 g x = ∑ i = 1 k a i g i g_x=\sum_{i=1}^{k}a_ig_i gx=i=1kaigi

有一个位移操作是这样的,假如上式,那么则有
g x + d = ∑ i = 1 k a i g i + d g_{x+d}=\sum_{i=1}^{k}a_ig_{i+d} gx+d=i=1kaigi+d

道理很简单,不证明了。

那么考虑在已知 g n 和 g m g_n和g_m gngm的情况下,表示 g n + m g_{n+m} gn+m

g n + m = ∑ i = 1 k a i g m + i g_{n+m}=\sum_{i=1}^{k}a_ig_{m+i} gn+m=i=1kaigm+i
这里的a1,a2…ak是gn的表示系数。
进一步,表示gm。
g n + m = ∑ i = 1 k a i ∑ j = 1 k b j g j + i g_{n+m}=\sum_{i=1}^{k}a_i\sum_{j=1}^kb_jg_{j+i} gn+m=i=1kaij=1kbjgj+i

这里的b1,b2…bk是gm的表示系数。

g n + m = ∑ i = 1 2 k g i ∑ u = 1 k a u b i − u g_{n+m}=\sum_{i=1}^{2k}g_i\sum_{u=1}^ka_ub_{i-u} gn+m=i=12kgiu=1kaubiu

后面的系数是标准的卷积形式,使用FFT加速即可计算。
假若能快速把1…2k的系数化成1…k的系数,就可以实现倍增求g。

暴力怎么做?枚举2k~k+1,强行将每一项的系数化为0,并操作1到k的系数使得式子恒等。这个复杂度是 O ( k 2 ) O(k^2) O(k2)的。

这好像多项式取模啊,能不能找出一个多项式,使得将系数多项式模这个多项式,就是直接对所有系数完成这一部分操作呢?

事实上,这个多项式就是 x k + 1 − f ( k ) x k − f ( k − 1 ) x k − 1 . . . − f ( 1 ) x x^{k+1}-f(k)x^k-f(k-1)x^{k-1}...-f(1)x xk+1f(k)xkf(k1)xk1...f(1)x.
f ( 1 ) , f ( 2 ) , f ( 3 ) . . . f ( k ) f(1),f(2),f(3)...f(k) f(1),f(2),f(3)...f(k) g k + 1 g_{k+1} gk+1的表示系数。

这似乎叫做这个线性递推的特征多项式。

总结

整理一下思路:
若得知g(n)的表达系数,则可以通过以下过程得g(2n)的表达系数:

  1. 将表达系数多项式平方,使用FFT加速。 O ( k log ⁡ k ) O(k \log k) O(klogk)
  2. 将求得的多项式对特征多项式求模。 O ( k log ⁡ k ) O(k \log k) O(klogk)

因此,整体复杂度也是 O ( k log ⁡ k ) O(k \log k) O(klogk)。要求得 g x g_x gx,只需要从 g 1 g_1 g1开始倍增。
复杂度 O ( k log ⁡ k log ⁡ n ) O(k \log k \log n) O(klogklogn)
当然你可以把上述过程写成一个g(n)与g(m)合并,得出g(n+m)的函数。这样在求g(2n+1)时,只需要额外把g(2n)与g(1)合并即可。

代码细节很多,打前深思熟虑。

常数优化

待更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值