矩阵乘法是个灰常灰常有用的东西!
先是定义:
矩阵乘法设A,B均为矩阵,An,Am分别表示矩阵A的行数和列数那么只有当Am=Bn的时候,A∗B才是可行的,设Am=Bn,C=A∗B,那么Cn=An,Cm=Bm,C(i,j)=∑A(i,k)∗B(k,j)
由此我们知道这是O( N3 )的,
似乎还有优化的,不过还是O( N3 )性价比高……
模板:
//val[N][N]存值,mod是模数,不需要时直接去掉即可
//重载了运算符,这样C++代码里更方便了
struct Matrix{
int val[N][N];
Matrix(){memset(val,0,sizeof(val));}
Matrix operator *(Matrix x){
Matrix c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
c.val[i][j]=(c.val[i][j]+val[i][k]*x.val[k][j]%mod)%mod;
return c;
}
};
接下来就是它的应用,矩阵乘法我就只讲两个应用了:
1.图邻接矩阵的x次方。
例题:bzoj1898
对于一张图,构造一个邻接矩阵A,A(i,j)=1当i->j这条边存在,不然就是0,
那么令
B=Ax
,B(i,j)表示i走到j恰好走x步的路径数。
很有用的东西!……原理不是非常懂,只能大概说说,
就是矩阵乘法是
C(i,j)=∑A(i,k)∗B(k,j)
,
就是i走到某一个点k的方案数和k走到j的方案数用乘法原理计算起来就行了。
2.优化某些有限项dp。
例题:poj3734
比较经典的是斐波那契数列
fib(i)=fib(i−1)+fib(i−2)
因为不管i是多少,永远只和(i-1),(i-2)项有关,
所以可以考虑能否去构造一个矩阵A,使得A*(i,i-1,i-2)->(i+1,i,i-1)
(i,i-1,i-2)表示构造出i,i-1,i-2有关的矩阵,具体应该有很多种方法。
又比如
f[i][j]=∑f[i−1][k],k满足某些条件,但是要满足k的关系不随i变化
由于i项只和(i-1)项有关,所以对第二维构造一个矩阵,
然后令某个矩阵和它相乘,固定地从(i-1)推到i,
矩阵乘法的过程直接快速幂就好了。
//z的初始化是令它为单位矩阵
Matrix ksm(Matrix a,int y){
Matrix z;
for (int i=1;i<=n;i++) z.val[i][i]=1;
while (y){
if (y&1) z=z*a;
y>>=1;a=a*a;
}
return z;
}