根据递推公式构造系数矩阵用于快速幂

转载自: https://blog.csdn.net/u012061345/article/details/52224623

简单的例子

Fibonacci数列

考虑FibonacciFibonacci数列, 

F(n)=F(n−1)+F(n−2)F(n)=F(n−1)+F(n−2)


将右边两项看做是一个列向量的形式,令 

Xn−1={Fn−1Fn−2}Xn−1={Fn−1Fn−2}


很容易得到XnXn的形式,即 

Xn={FnFn−1}Xn={FnFn−1}


现在的任务就是找到一个系数矩阵AA,使得AXn−1=XnAXn−1=Xn,且AA需与nn无关。 
如果能够找到这个AA,则易知An−1X1=XnAn−1X1=Xn,于是可以利用矩阵快速幂计算出XnXn。这样就可以在O(logn)O(log⁡n)的时间内计算出指定的FibonacciFibonacci数。 
这个矩阵很容易找,观察易得 

A={1110}(1)(1)A={1110}

Fibonacci数列变种

推广一下,如果令Fn=aFn−1+bFn−2Fn=aFn−1+bFn−2,则系数矩阵为 

A={a1b0}(2)(2)A={ab10}

利用二项式展开构造矩阵

计算k次方和

FibonacciFibonacci数列只是最简单的例子,对于稍微复杂一点的例子,二项式展开是常用的一项技术。 
考虑计算: 

Sn=∑i=1nikSn=∑i=1nik


易得 

Sn=nk+Sn−1Sn=nk+Sn−1


如果仿照FibonacciFibonacci数列,令 

Xn−1={nkSn−1}Xn−1={nkSn−1}


则 

Xn={(n+1)kSn}Xn={(n+1)kSn}


此时,可求出 

A=⎧⎩⎨(n+1n)k101⎫⎭⎬A={(n+1n)k011}


这个系数矩阵很明显是不能用的,因为它与nn有关,无法将递推公式转化为矩阵的幂运算。 
这里需要使用二项式展开。 

Sn=(n−1+1)k+Sn−1=C0k(n−1)k+C1k(n−1)k−1+⋯+Ckk+Sn−1Sn=(n−1+1)k+Sn−1=Ck0(n−1)k+Ck1(n−1)k−1+⋯+Ckk+Sn−1


此时,如果令 

Xn−1=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(n−1)k(n−1)k−1⋮(n−1)0Sn−1⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn−1={(n−1)k(n−1)k−1⋮(n−1)0Sn−1}


则有 

Xn=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪nknk−1⋮n0Sn⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn={nknk−1⋮n0Sn}


现在的任务与刚才一样,找到一个系数矩阵AA,使得AXn−1=XnAXn−1=Xn,且AA需与nn无关。 
有关SnSn的递推公式实际上就指明了AA的最后一行。而利用二项式展开很容易得到其他行。 
有 

A=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪C0k0⋮0C0kC1kC0k−1⋮⋯C1k⋯⋯⋱⋯⋯CkkCk−1k−1⋮C00Ckk00⋮01⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(3)(3)A={Ck0Ck1⋯Ckk00Ck−10⋯Ck−1k−10⋮⋮⋱⋮⋮0⋯⋯C000Ck0Ck1⋯Ckk1}


最后有 

An−1X1=XnAn−1X1=Xn


且 

X1={1 1 ⋯ 1}TX1={1 1 ⋯ 1}T


利用该系数矩阵可以在O(k3logn)O(k3log⁡n)时间内计算出kk次方的和。

更一般的例子

再考虑一个一般情况:

Sn=∑i=1n(ai+b)kSn=∑i=1n(ai+b)k


与刚才几乎一模一样,有 

Sn=[a(n−1)+(a+b)]k+Sn−1=C0kak(n−1)k+C1kak−1(a+b)(n−1)k−1+⋯+Ckk(a+b)k+Sn−1Sn=[a(n−1)+(a+b)]k+Sn−1=Ck0ak(n−1)k+Ck1ak−1(a+b)(n−1)k−1+⋯+Ckk(a+b)k+Sn−1


剩下的步骤,也几乎完全与之前的一样,令 

Xn−1=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(n−1)k(n−1)k−1⋮(n−1)0Sn−1⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn−1={(n−1)k(n−1)k−1⋮(n−1)0Sn−1}


则 

Xn=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪nknk−1⋮n0Sn⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn={nknk−1⋮n0Sn}


同样,有关SnSn的递推公式实际上就指明了AA的最后一行,其他行则利用二项式展开得到。 
有 

A=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪C0k0⋮0C0kakC1kC0k−1⋮⋯C1kak−1(a+b)⋯⋯⋱⋯⋯CkkCk−1k−1⋮C00Ckk(a+b)k00⋮01⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(4)(4)A={Ck0Ck1⋯Ckk00Ck−10⋯Ck−1k−10⋮⋮⋱⋮⋮0⋯⋯C000Ck0akCk1ak−1(a+b)⋯Ckk(a+b)k1}

更复杂的例子

假设要计算如下和式: 

Sn=∑i=1nikkiSn=∑i=1nikki


同样,将其写成递推公式,有 

Sn=nkkn+Sn−1=(n−1+1)kk(n−1)+1+Sn−1=C0k(n−1)kk(n−1)+1+C1k(n−1)k−1k(n−1)+1+⋯+Ckkk(n−1)+1+Sn−1Sn=nkkn+Sn−1=(n−1+1)kk(n−1)+1+Sn−1=Ck0(n−1)kk(n−1)+1+Ck1(n−1)k−1k(n−1)+1+⋯+Ckkk(n−1)+1+Sn−1


将与nn有关的项抽出来作为列向量,令 

Xn−1=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(n−1)kk(n−1)+1(n−1)k−1k(n−1)+1⋮(n−1)0k(n−1)+1Sn−1⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn−1={(n−1)kk(n−1)+1(n−1)k−1k(n−1)+1⋮(n−1)0k(n−1)+1Sn−1}


则 

Xn=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪nkkn+1nk−1kn+1⋮n0kn+1Sn⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪Xn={nkkn+1nk−1kn+1⋮n0kn+1Sn}

同样,有关SnSn的递推公式说明了系数矩阵AA的最后一行。而其他行仍然可以由二项式展开得到,只是相差了一个系数kk而已,这很容易解决。 
最后,有 

A=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪kC0k0⋮0C0kkC1kkC0k−1⋮⋯C1k⋯⋯⋱⋯⋯kCkkkCk−1k−1⋮kC00Ckk00⋮01⎫⎭⎬⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪(5)(5)A={kCk0kCk1⋯kCkk00kCk−10⋯kCk−1k−10⋮⋮⋱⋮⋮0⋯⋯kC000Ck0Ck1⋯Ckk1}

部分题目

POJ3070利用了矩阵1,hdu3369利用了矩阵3和4,hdu3483利用了矩阵5。

猜你喜欢

转载自blog.csdn.net/qian2213762498/article/details/82177690