洛谷 P3390 【模板】矩阵快速幂
Description
- 给定n*n的矩阵A,求A^k
- n<=100, k<=10^12, |矩阵元素|<=1000
Input
第一行,n,k
第2至n+1行,每行n个数,第i+1行第j个数表示矩阵第i行第j列的元素
Output
输出A^k
共n行,每行n个数,第i行第j个数表示矩阵第i行第j列的元素,每个元素模10^9+7
Sample Input
2 1
1 1
1 1
Sample output
1 1
1 1
题解:
算法如题所示。
矩阵是什么?
- 就是一个矩阵,字面意思。
矩阵如何运算?
- 加法:对于两个形一样的矩阵,对应的位置相加就好了
- 减法:同加法一样
- 除法:貌似实际中是有的,但是OI中不常用,不讨论
- 乘法:矩阵乘法是重头戏,她有个前提条件,两个矩阵相乘,必须满足(n, m) * (m, p) = (n, p)。(前一个个数是行,后一个数是列)。就像这样↓(2, 2) * (2, 1) = (2, 1)
\[ \left\{ \begin{matrix} 1 & 1 \\ 0 & 3 \\ \end{matrix} \right\} * \left\{ \begin{matrix} 2 \\ 2 \\ \end{matrix} \right\} = \left\{ \begin{matrix} 1 * 2 + 1 * 2 \\ 0 * 2 + 3 * 2 \\ \end{matrix} \right\} \]
\[ \left[ \begin{matrix} 2 \\ 2 \\ \end{matrix} \right] * \left[ \begin{matrix} 1 & 1 \\ 0 & 3 \\ \end{matrix} \right] != \left[ \begin{matrix} 1 * 2 + 1 * 2 \\ 0 * 2 + 3 * 2 \\ \end{matrix} \right] 但这样写就是错的! \]
因为(2, 1) * (2, 2)。1 != 2,不符合矩阵乘法意义。
- 所以由此还可以推出:矩阵不满足交换律
矩阵有什么用?
- 优化递推式。
- 我怎么知道什么时候要优化递推式?
- 数据范围极大,比如10的18次方什么的,O(n)都过不去的
- 怎么优化?
- 一般优化就是优化在矩阵快速幂上,但写完快速幂之后怎么优化,转这里
- 所以现在任务就是写矩阵快速幂!
矩阵快速幂:
- 首先易得矩阵乘法是满足结合律的,所以快速幂的形跟普通的快速幂没有什么区别,直接给出代码,细细品味一下。(反正我看了一篇大概就懂了)
#include <iostream> #include <cstdio> #define maxn 105 #define mod 1000000007 #define LL long long using namespace std; struct Obj {LL a[maxn][maxn];} x, d; LL n, p; Obj mul(Obj x, Obj y) { Obj r; for(LL i = 1; i <= n; i++) for(LL j = 1; j <= n; j++) r.a[i][j] = 0; for(LL i = 1; i <= n; i++) for(LL j = 1; j <= n; j++) for(LL k = 1; k <= n; k++) r.a[i][j] += (x.a[i][k] % mod * y.a[k][j] % mod) % mod, r.a[i][j] %= mod; return r; } Obj power(Obj x, LL p) { Obj r = d, base = x; while(p) { if(p & 1) r = mul(r, base); base = mul(base, base); p >>= 1; } return r; } int main() { cin >> n >> p; for(LL i = 1; i <= n; i++) for(LL j = 1; j <= n; j++) cin >> x.a[i][j]; for(LL i = 1; i <= n; i++) d.a[i][i] = 1; Obj ans = power(x, p); for(LL i = 1; i <= n; i++) { for(LL j = 1; j <= n; j++) cout << ans.a[i][j] % mod << ' '; cout << endl; } return 0; }