矩阵乘法可是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
x2−ax−b=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
x2−2x−3=0⇒x1=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.
∴{3c1−c2=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)=3n−2(−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,fn−1)⋅(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(n−1)+a2f(n−2)+...+akf(n−k)
那么显然,
(
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,fn−1,...,fn−k+1,fn−k)⋅⎝⎜⎜⎜⎜⎛a1a2...ak−1ak10...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,...,fn−k+2,fn−k+1)
是不是非常神奇?这样就可以用矩阵快速幂了。代码就不放了……