row 行
column 列
非对角线都是0,对角线上都是1,类似乘法中的1
一般用I表示
单位矩阵乘以任何矩阵A,都等于A本身
AI = IA = A
求矩阵A的逆
矩阵A和单位矩阵连起来组成一个n行2n列的矩阵
通过行初等变换,高斯消元,让矩阵A变成单位矩阵I
做行初等变换时,一共2n列
如果原本的矩阵A变成了单位矩阵,那么原本的单位矩阵就变成了A的逆矩阵
https://en.wikipedia.org/wiki/Cayley–Hamilton_theorem
绝大多数涉及到矩阵的题目都是 矩阵乘法快速幂
少量题目利用矩阵的性质,维护前缀和或线段树
https://www.luogu.com.cn/problem/P6009
Bessie 最近参加了一场 USACO 竞赛,遇到了以下问题。当然 Bessie 知道怎么做。那你呢?
考虑一个仅由范围在 ()之间的整数组成的长为 的序列 ()。给定 ( )个形式为 ()的询问。对于每个询问,计算 中不下降子序列的数量模 的余数。
的一个不下降子序列是一组索引 (),满足 以及 。确保你考虑了空子序列!
输入的第一行包含两个空格分隔的整数 和 。
第二行包含 个空格分隔的整数 。
第三行包含一个整数 。
以下 行每行包含两个空格分隔的整数 和 。
对于每个询问 ,你应当在新的一行内输出 的不下降子序列的数量模 的余数。
5 2
1 2 1 1 2
3
2 3
4 5
1 5
3
4
20
样例解释
对于第一个询问,不下降子序列为 、 和 。 不是一个不下降子序列,因为 。
对于第二个询问,不下降子序列为 、、 和 。
子任务
#include <bits/stdc++.h> using namespace std; int n, m, x; const int mod = 1000000007; int p[50020][20][20], q[50020][20][20]; int f[20][20][20]; int g[20][20][20]; void amul(int a[20][20], int b[20][20], int c[20][20]) { for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { c[i][j] = 0; } } for (int i = 0; i < m; i++) { for (int k = 0; k < m; k++) { if (a[i][k] == 0) { continue; } for (int j = 0; j < m; j++) { c[i][j] = (c[i][j] + (long long)a[i][k] * b[k][j]) % mod; } } } } void bmul(int a[20][20], int b[20][20], int c[20][20]) { for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { c[i][j] = 0; } } for (int j = 0; j < m; j++) { for (int k = 0; k < m; k++) { if (b[k][j] == 0) { continue; } for (int i = 0; i < m; i++) { c[i][j] = (c[i][j] + (long long)a[i][k] * b[k][j]) % mod; } } } } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { f[i][j][j] = 1; g[i][j][j] = 1; } for (int j = 0; j <= i; j++) { f[i][j][i] += 1; g[i][j][i] = (g[i][j][i] + (mod - 1) / 2) % mod; } } for (int i = 0; i < m; i++) { p[0][i][i] = 1; q[0][i][i] = 1; } for (int i = 1; i <= n; i++) { scanf("%d", &x); x--; bmul(p[i - 1], f[x] , p[i]); amul(g[x] , q[i - 1], q[i]); } int t, l, r; scanf("%d", &t); for (int i = 0; i < t; i++) { scanf("%d%d", &l, &r); l--; int ans = 0; for (int i = 0; i < m; i++) { for (int j = 0; j < m; j++) { ans = (ans + (long long)q[l][0][i] * p[r][i][j]) % mod; } } printf("%d\n", ans); } return 0; }