基础数论算法(八) 矩阵乘法与线性齐次递推公式的快速求值

矩阵乘法可是zhx钦定说考的可能性挺大的东西!


###矩阵乘法
一个n*m的矩阵乘一个m*p的矩阵会得到一个n*p的矩阵。
因此有一道区间dp模板叫矩阵链乘法,不过这个不是重点。
矩阵乘法如果要简单的说,就是行乘每一列放在对应的行上。这么说可能不太清楚,不过我觉得代码比一堆 ∑ \sum 清晰的多。

void multi(int m,int n,int p){
    for(int i=0;i<m;++i)
        for(int j=0;j<p;++j)
            for(int k=0;k<n;++k)
                c[i][j]+=a[i][k]*b[k][j];            
}


###特征根方程
为什么要提特征根方程?因为觉得很有趣如果解出来是整数说不定可以少些五行矩阵乘法。
对于f(n)=af(n-1)+bf(n-2)这种递推公式,我们可以用特征根方程求出通项。顺便一提,这种方法写大题的时候不能用,老老实实待定系数吧。
首先,把原通项写成f(n)-af(n-1)-bf(n-2)=0的形式。
接下来,解一个方程: x 2 − a x − b = 0 x^2-ax-b=0 x2axb=0,假设解为 x 1 , x 2 x_1,x_2 x1,x2
那么我们称这两个解是这个数列的特征根。
这里要注意,如果无实数解,那么这个数列一般是具有周期性的。
如果 x 1 ≠ x 2 x_1\neq x_2 x1=x2,那么 a n = c 1 x 1 n + c 2 x 2 n a_n=c_1x_1^n+c_2x_2^n an=c1x1n+c2x2n,其中 c 1 , c 2 c_1,c_2 c1,c2带进去两个数就知道了。
例如:f(n)=2f(n-1)+3f(n-2),f(1)=5,f(2)=7
x 2 − 2 x − 3 = 0 ⇒ x 1 = 3 , x 2 = − 1 x^2-2x-3=0 \Rightarrow x_1=3,x_2=-1 x22x3=0x1=3,x2=1
∴ f ( n ) = 3 n c 1 + ( − 1 ) n c 2 \therefore f(n)=3^nc_1+(-1)^nc_2 f(n)=3nc1+(1)nc2
∴ { 3 c 1 − c 2 = 5 9 c 1 + c 2 = 7 \therefore \left \{\begin{matrix}3c_1-c2=5\\ 9c_1+c_2=7\end{matrix}\right. {3c1c2=59c1+c2=7
解之得 c 1 = 1 , c 2 = − 2 c_1=1,c_2=-2 c1=1,c2=2
f ( n ) = 3 n − 2 ( − 1 ) n f(n)=3^n-2(-1)^n f(n)=3n2(1)n,要求的话带个快速幂美滋滋。
不过问题还是有的。一个是 x 1 = x 2 x_1=x_2 x1=x2的情况很糟心,一个是如果我们的特征根是无理数,而且要求一个很大的数取模,那么这种方法就会不适用。因此我们必须提出用矩阵乘法写的普适性更强的做法。


###用矩阵乘法优化的线性齐次递推公式求值
首先我们来看一个神奇的东西。
对斐波那契数列,
( f n , f n − 1 ) ⋅ ( 1 1 1 0 ) = ( f n + 1 , f n ) \left( f_{n},f_{n-1}\right) \cdot \left( \begin{matrix} 1& 1\\ 1& 0\end{matrix} \right)=(f_{n+1},f_n) (fn,fn1)(1110)=(fn+1,fn)
这样的话我们可以在常数时间内求出这个通项的下一项。而如果要求第n项,就相当于对这个矩阵进行幂运算。
有没有想到些什么?没错,见幂就开始快速幂。复杂度logn,比线性求不知道高到哪里去了。
那么能不能进一步推广?当然可以。
如果 f ( n ) = a 1 f ( n − 1 ) + a 2 f ( n − 2 ) + . . . + a k f ( n − k ) f(n)=a_1f(n-1)+a_2f(n-2)+...+a_kf(n-k) f(n)=a1f(n1)+a2f(n2)+...+akf(nk)
那么显然,
( f n , f n − 1 , . . . , f n − k + 1 , f n − k ) ⋅ ( a 1 1 0 . . . 0 0 a 2 0 1 . . . 0 0 . . . . . . . . . . . . . . . . . . a k − 1 0 0 . . . 0 1 a k 0 0 . . . 0 0 ) = \left(f_n,f_{n-1},...,f_{n-k+1},f_{n-k}\right) \cdot \left( \begin{matrix} a_1&1&0&...&0&0 \\a_2&0 &1&...&0&0\\...&...&...&...&...&...\\a_{k-1}&0&0&...&0&1\\a_k&0&0&...&0&0\end{matrix} \right)= (fn,fn1,...,fnk+1,fnk)a1a2...ak1ak10...0001...00...............00...0000...10=
( f n + 1 , f n , . . . , f n − k + 2 , f n − k + 1 ) (f_{n+1},f_n,...,f_{n-k+2},f_{n-k+1}) (fn+1,fn,...,fnk+2,fnk+1)
是不是非常神奇?这样就可以用矩阵快速幂了。代码就不放了……

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值