矩阵乘法写法研究

矩阵乘法写法研究

固定大小,array 的别名

template <size_t N, size_t M>
using matrix = array<array<int, M>, N>;
int main() {
  matrix<2, 3> a = {{ {1, 2, 3}, {4, 5, 6} }};
  matrix<2, 3> c = {-1, -2, -3, -4, -5, -6};
  return 0;
}
  1. 所有 size_t 都是必要的,不能改成 int。对应的重载运算符等也都要写为 size_t
  2. 不要把有关这个别名的函数封到命名空间里。因为那是别名,不是新类型,ADL 不会查找命名空间里的函数。
  3. 构造矩阵的时候,要么在外层额外加一层花括号(a),要么只加一层花括号(c)。
  4. 构造矩阵的时候,可以只写某一行的前几项,剩下的都会是零,但这样就要用 a 那种写法。特别地,= {} 就是全零矩阵。

不要继承 array,不然会无法使用聚合初始化,还不如这样写。

固定大小,原生数组

template <int N, int M>
struct matrix {
  int arr[N][M];
  auto& operator[](int i) { return arr[i]; }
  auto& operator[](int i) const { return arr[i]; }
};
int main() {
  matrix<2, 3> a = {{ {1, 2, 3}, {4, 5, 6} }};
  matrix<2, 3> c = {-1, -2, -3, -4, -5, -6};
  return 0;
}

和上一个的区别是,这样写就可以不用写一堆 size_t 而可以全写 int 了。另外矩阵的构造方式还是不变的。

不定大小,继承 vector

struct matrix : vector<vector<mint>> {
  matrix(size_t n, size_t m) : vector(n, vector<mint>(m)) {}
  matrix(initializer_list<vector<int>> init) : vector(init) {}
};
int main() {
  matrix a = {{1, 2, 3}, {4, 5, 6}};
  matrix b(2, 3);
  return 0;
}

这应该是相对人类的一种写法了,用正统的 initializer_list 写,不过要注意 initializer_list 里面的类型是要写 vector<int>,不要搞错了。

完整代码

固定大小 array 别名:

#include <bits/stdc++.h>
using namespace std;

template <size_t N, size_t M>
using matrix = array<array<int, M>, N>;

template <size_t N, size_t M, size_t R>
matrix<N, R> operator*(const matrix<N, M>& lhs, const matrix<M, R>& rhs) {
  matrix<N, R> res = {};
  for (size_t i = 0; i < N; i++) {
    for (size_t k = 0; k < R; k++) {
      for (size_t j = 0; j < M; j++) {
        res[i][k] += lhs[i][j] * rhs[j][k];
      }
    }
  }
  return res;
}

template <size_t N, class T>
matrix<N, N> qpow(matrix<N, N> a, T b) {
  matrix<N, N> res = {};
  for (size_t i = 0; i < N; i++) res[i][i] = 1;
  while (b) {
    if (b & 1) res = res * a;
    if (b >>= 1) a = a * a;
  }
  return res;
}

int main() {
  matrix<3, 3> a = {{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
  }};
  matrix<3, 3> c = {
    -1, -2, -3,
    -4, -5, -6,
    -7, -8, -9
  };

  auto b = qpow(a, 5) * c;
  return 0;
}

固定大小原生数组:

#include <bits/stdc++.h>
using namespace std;

template <int N, int M>
struct matrix {
  int arr[N][M];
  auto& operator[](int i) { return arr[i]; }
  auto& operator[](int i) const { return arr[i]; }
};

template <int N, int M, int R>
matrix<N, R> operator*(const matrix<N, M>& lhs, const matrix<M, R>& rhs) {
  matrix<N, R> res = {};
  for (int i = 0; i < N; i++) {
    for (int k = 0; k < R; k++) {
      for (int j = 0; j < M; j++) {
        res[i][k] += lhs[i][j] * rhs[j][k];
      }
    }
  }
  return res;
}

template <int N, class T>
matrix<N, N> qpow(matrix<N, N> a, T b) {
  matrix<N, N> res = {};
  for (int i = 0; i < N; i++) res[i][i] = 1;
  while (b) {
    if (b & 1) res = res * a;
    if (b >>= 1) a = a * a;
  }
  return res;
}

int main() {
  matrix<3, 3> a = {{
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
  }};
  matrix<3, 3> c = {
    -1, -2, -3,
    -4, -5, -6,
    -7, -8, -9
  };

  auto b = qpow(a, 5) * c;
  return 0;
}

不定大小,继承 vector

struct matrix : vector<vector<mint>> {
  matrix(size_t n, size_t m) : vector(n, vector<mint>(m)) {}
  matrix(initializer_list<vector<int>> init) : vector(init) {}
};
matrix operator*(const matrix& lhs, const matrix& rhs) {
  matrix res(lhs.size(), rhs[0].size());
  for (int i = 0; i < (int)lhs.size(); i++) {
    for (int j = 0; j < (int)rhs.size(); j++) {
      for (int k = 0; k < (int)rhs[0].size(); k++) {
        res[i][k] += lhs[i][j] * rhs[j][k];
      }
    }
  }
  return res;
}
matrix qpow(matrix a, LL b) {
  int n = (int)a.size();
  matrix r(n, n);
  for (int i = 0; i < n; i++) r[i][i] = 1;
  while (b) {
    if (b & 1) r = r * a;
    if (b >>= 1) a = a * a;
  }
  return r;
}
posted @ 2025-10-15 16:50  caijianhong  阅读(63)  评论(0)    收藏  举报