OI模板 矩阵运算
矩阵乘法
const int N = 1, Mod = 1e9 + 7;
struct Matrix{
int n, m;
long long a[N][N];
Matrix(int x, int y, int op) : n(x), m(y) {
if(op >= 0){
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= m; ++ j)
a[i][j] = op;
} else if(op == -1){//单位矩阵
memset(a, 0, sizeof(a));
for(int i = 1; i <= n; ++ i)
a[i][i] = 1;
}
}
Matrix() {}
void read(int x, int y){
n = x, m = y;
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= m; ++ j)
scanf("%lld", &a[i][j]);
return ;
}
void print(){
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j)
printf("%lld ", a[i][j]);
puts("");
}
return ;
}
Matrix operator * (const Matrix &b) const {
Matrix c(n, b.m, 0);
for(int i = 1; i <= n; ++ i)
for(int j = 1; j <= b.m; ++ j)
for(int k = 1; k <= m; ++ k)
c.a[i][j] += a[i][k] % Mod * b.a[k][j] % Mod,
c.a[i][j] = (c.a[i][j] + Mod) % Mod;
return c;
}
};
矩阵快速幂
inline Matrix QuickPow(Matrix a, long long k){
Matrix ans(a.n, a.n, -1);//初始化为单位矩阵
while(k){
if(k & 1) ans = ans * a;
a = a * a;
k >>= 1;
}
return ans;
}
另一种写法:
inline Matrix QuickPow(Matrix a, long long k){
Matrix ans = a; -- k;
while(k){
if(k & 1) ans = ans * a;
a = a * a;
k >>= 1;
}
return ans;
}
矩阵加速线性递推式
斐波那契数列
F i b n = { 1 ( n ≤ 2 ) F i b n − 1 + F i b n − 2 ( n ≥ 3 ) Fib_n = \begin{cases} 1~(n\leq2) \\ Fib_{n-1}+Fib_{n-2}~(n \geq 3) \end{cases} Fibn={1 (n≤2)Fibn−1+Fibn−2 (n≥3)
[ F i b 2 F i b 1 ] × [ 1 1 1 0 ] n − 2 = [ F i b n F i b n − 1 ] \begin{bmatrix} Fib_{2}&Fib_{1} \end{bmatrix}\times\begin{bmatrix} 1&1 \\ 1&0 \end{bmatrix}^{n-2} = \begin{bmatrix} Fib_{n}&Fib_{n-1} \end{bmatrix} [Fib2Fib1]×[1110]n−2=[FibnFibn−1]
inline long long Fibonacci(long long k){
if(k <= 2) return 1;
Matrix Ans(1, 2, 0), Base(2, 2, 0);
Ans.a[1][1] = Ans.a[1][2] = 1;
Base.a[1][1] = Base.a[1][2] = Base.a[2][1] = 1;
Base.a[2][2] = 0;
return (Ans * QuickPow(Base, k - 2)).a[1][1];
}
广义斐波那契数列
F i b n = { a 1 ( n = 1 ) a 2 ( n = 2 ) p ∗ F i b n − 1 + q ∗ F i b n − 2 ( n ≥ 3 ) Fib_n = \begin{cases} a_1~(n = 1) \\ a_2~(n = 2) \\ p * Fib_{n-1} + q * Fib_{n-2}~(n \geq 3) \end{cases} Fibn=⎩⎪⎨⎪⎧a1 (n=1)a2 (n=2)p∗Fibn−1+q∗Fibn−2 (n≥3)
[ a 2 a 1 ] × [ p 1 q 0 ] n − 2 = [ F i b n F i b n − 1 ] \begin{bmatrix} a_{2}&a_{1} \end{bmatrix}\times\begin{bmatrix} p&1 \\ q&0 \end{bmatrix}^{n-2} = \begin{bmatrix} Fib_{n}&Fib_{n-1} \end{bmatrix} [a2a1]×[pq10]n−2=[FibnFibn−1]
Luogu P1939 【模板】矩阵加速(数列)
a n = { 1 ( n ∈ { 1 , 2 , 3 } ) a n − 1 + a n − 3 ( n ≥ 4 ) a_n = \begin{cases} 1~(n\in \{1,2,3\}) \\ a_{n-1}+a_{n-3}~(n \geq 4) \end{cases} an={1 (n∈{1,2,3})an−1+an−3 (n≥4)
[ a 3 a 2 a 1 ] ∗ [ 1 1 0 0 0 1 1 0 0 ] n − 3 = [ a n a n − 1 a n − 2 ] \begin{bmatrix} a_3&a_2&a_1 \end{bmatrix} * \begin{bmatrix} 1&1&0 \\ 0&0&1 \\ 1&0&0 \end{bmatrix}^{n-3} = \begin{bmatrix} a_n&a_{n-1}&a_{n-2} \end{bmatrix} [a3a2a1]∗⎣⎡101100010⎦⎤n−3=[anan−1an−2]
inline long long Getkth(long long k){
if(k <= 3) return 1;
Matrix Ans(1, 3, 0), Base(3, 3, 0);
Ans.a[1][1] = Ans.a[1][2] = Ans.a[1][3] = 1;
Base.a[1][1] = Base.a[1][2] = Base.a[2][3] = Base.a[3][1] = 1;
return (Ans * QuickPow(Base, k - 3)).a[1][1];
}
矩阵加速 DP
一张有向图求某点到另外一点定长路线 k k k 的方案数
邻接矩阵的 k k k 次方就为答案,第 i , j i,j i,j 位的数字表示点 i i i 到点 j j j 长度为 k k k 的路径数。
如果有原地踏步增加边 ( i , i ) (i,i) (i,i),有停止增加边 ( i , 0 ) (i,0) (i,0)。
例题:Luogu P5789 [TJOI2017]可乐(数据加强版)
一张有向图求某点到另外一点定长路线 k k k 的最小花费
将矩阵乘法中乘法一句换为 c.a[i][j] = min(c.a[i][j], a[i][k] + b.a[k][j]);
,邻接表以及乘法中
c
c
c 数组初始化为
inf
\inf
inf 即可。
邻接矩阵的 k k k 次方就为答案,第 i , j i,j i,j 位的数字表示点 i i i 到点 j j j 长度为 k k k 的最小花费。