矩阵表示
ICPC中的矩阵运算一般为方阵
struct Matrix{
ll matrix[105][105];
};
int n; //矩阵的阶数
矩阵初等变换
- 交换矩阵的两行或两列(对调 i , j i,j i,j,两行记为 r i ⟺ r j r_i \Longleftrightarrow r_j ri⟺rj)
- 以一个非零数 k k k乘矩阵的某一行(列)所有元素(第 i i i行乘以 k k k记为 r i ∗ k r_i*k ri∗k )
- 把矩阵的某一行(列)所有元素乘以一个数 k k k后加到另一行(列)对应的元素(第 j j j行乘以 k k k加到第 i i i行记为 r i + k ∗ r j r_i+ k*r_j ri+k∗rj )
矩阵加法
Matrix add(Matrix a, Matrix b) {
Matrix ans;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
ans.matrix[i][j] = (a.matrix[i][j] + b.matrix[i][j]) % Mod;
return ans;
}
矩阵乘法
条件:仅考虑方阵相乘;口诀:前行乘后列
例如,对于 A × B = C , a i , j ∈ A , b i , j ∈ B , c i , j ∈ C A×B=C,a_{i,j}∈A,b_{i,j}∈B,c_{i,j}∈C A×B=C,ai,j∈A,bi,j∈B,ci,j∈C,则 c i , j = a i , 1 ∗ b 1 , j + a i , 2 ∗ b 2 , j + . . . + a i , n ∗ b n , j c_{i,j}=a_{i,1}*b_{1,j}+a_{i,2}*b_{2,j}+...+a_{i,n}*b_{n,j} ci,j=ai,1∗b1,j+ai,2∗b2,j+...+ai,n∗bn,j
Matrix mul(Matrix a, Matrix b) {
Matrix ans;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++){
ans.matrix[i][j]=0;
for (int k = 1; k <= n; k++) {
ans.matrix[i][j] += a.matrix[i][k] * b.matrix[k][j] % Mod;
ans.matrix[i][j] %= Mod;
}
}
return ans;
}
//矩阵快速幂
//如果求的是指数公差为1的连续矩阵,使用中间变量代替快速幂可以节省大量时间
Matrix qkp(Matrix mx, ll x) {
Matrix ans;
memset(ans.matrix, 0, sizeof ans.matrix);
for (int i = 1; i <= n; i++) ans.matrix[i][i] = 1;
while (x) {
if (x & 1) ans = mul(ans, mx);
mx = mul(mx, mx);
x >>= 1;
}
return ans;
}
矩阵的逆
A A A可逆的充要条件为 ∣ A ∣ ≠ 0 |A|\neq0 ∣A∣=0,其中 ∣ A ∣ |A| ∣A∣称为矩阵的行列式
对于 n n n阶方阵 A A A ,若存在一个 n n n阶方阵 B B B ,使得 A B = B A = E AB=BA=E AB=BA=E ,其中 E E E为单位矩阵,则称 A A A为可逆阵且称 B B B为 A A A的逆矩阵,记作 A − 1 A^{-1} A−1
二阶方阵
特殊的,对于二阶方阵 [ a b c d ] { \left[ \begin{array}{ccc} a & b \\ c & d \\ \end{array} \right ]} [acbd],其逆矩阵为 1 a d − b c [ d − b − c a ] \frac{1}{ad-bc}{ \left[ \begin{array}{ccc} d & -b \\ -c & a \\ \end{array} \right ]} ad−bc1[d−c−ba]
高阶方阵
定义
A ∗ A^* A∗称为 A A A的伴随矩阵,其求法为 A i , j = ( − 1 ) i + j ∣ B ∣ A_{i,j}=(-1)^{i+j}|B| Ai,j=(−1)i+j∣B∣,其中 B B B矩阵是除去第 i i i行第 j j j列剩下的数按照上下左右不变的关系凑成的 n − 1 n-1 n−1阶矩阵。那么 A − 1 = 1 ∣ A ∣ A ∗ A^{-1}=\frac{1}{|A|}A^* A−1=∣A∣1A∗
求解
-
将 A A A的同阶逆矩阵和 A A A放在一起形成 n ∗ 2 n n*2n n∗2n的新矩阵 B B B
-
对 B B B进行矩阵初等变换使 B B B的左半部分变为单位矩阵
-
此时 B B B的右半部分即为逆矩阵 A − 1 A^{-1} A−1
即 A − 1 ∗ ( A I ) = I A − 1 A^{-1}*(AI)=IA^{-1} A−1∗(AI)=IA−1
使用高斯-约旦消元即可解决,时间复杂度 O ( n 3 ) O(n^3) O(n3)
const int Mod = 1e9 + 7;
ll a[505][1005];
ll qkp(ll x, ll n, ll p) {
ll ans = 1;
x %= p;
while (n) {
if (n & 1) ans = ans * x % p;
x = x * x % p;
n >>= 1;
}
return ans;
}
void print(int n,int m){
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
printf("%lld%c", a[i][j], j == 2 * n ? '\n' : ' ');
}
}
bool gauss_jordan(int n, int m) {
int tmp;
for (int i = 1; i <= n; i++) {
tmp = i;
while (!a[tmp][i] && tmp <= n) tmp++;
if (tmp == n + 1) return false;
for (int j = 1; j <= m; j++)
swap(a[i][j], a[tmp][j]);
ll p = a[i][i], inv = qkp(a[i][i], Mod - 2, Mod);
for (int j = 1; j <= m; j++)
a[i][j] = a[i][j] * inv % Mod;
for (int j = 1; j <= n; j++) {
if (i != j) {
ll q = a[j][i];
for (int k = 1; k <= m; k++)
a[j][k] = (a[j][k] - q * a[i][k] % Mod + Mod) % Mod;
}
}
//print(n,m);
}
return true;
}