---
# System prepended metadata

title: 快速冪&矩陣乘法&矩陣快速冪
tags: [自主學習, 演算法]

---

# 快速冪&矩陣乘法&矩陣快速冪
## 快速冪
### 次方
平常我們在計算$n^m$時
我們式攤開成$n*n*n*n*n*n*...*n$總共$m$個$n$
時間複雜度式$O(m)$
這個時間複雜度不差，但還可以更好

### 快速冪概念
我們把$n^m$換成
的$m$拆成二進位
例如$n^{13}$，13換成二進位是1101，也就是$2^3 * 1 + 2^2 * 1 + 2^1 * 0 + 2^0 * 1$
所以$n^{13}$換成
$\implies n^{2^3 * 1 + 2^2 * 1 + 2^1 * 0 + 2^0 * 1}$
$\implies n^{2^3} * n^{2^2} * n^{2^1 * 0} * n^{2^0}$

計算$n^m$
從$2^0$開始$2^1 \implies 2^2 \implies ... \implies 2^i \implies ... \implies 2^m$
如果二進為中的第$i$個是$1$就乘上去，是$0$就不乘
所以時間複雜度是以$2$為底的$log \implies O(logm)$

### 實作
```cpp=
int qpow(int a, int b){//a^b
    int r = 1;
    int n = b;
    for(;n;n=n >> 1){
        if(n & 1)r = r * a;
        a = a * a;
    }
    return r;
}
```

## 矩陣乘法
矩陣 $A = \left [ \begin{array}{1} a_{11} & a_{12}\\a_{21} & a_{22}\end{array}\right],\; B = \left [ \begin{array}{1} b_{11} & b_{12}\\b_{21} & b_{22}\end{array}\right]$

則 $AB = \left [ \begin{array}{1} a_{11}\times b_{11} + a_{12}\times b_{21} & a_{11}\times b_{12} + a_{12}\times b_{22}\\a_{21}\times b_{11} + a_{22}\times b_{21} & a_{21}\times b_{12} + a_{22}\times b_{22}\end{array}\right]$

### 注意事項
第一個矩陣的列數和第二個矩陣的行數要一樣
算出的矩陣的列是第二個矩陣的列，行是第一個矩陣了行

$\left [ \begin{array}{1} A_{1} \\ A_{2} \\ A_{3} \\\vdots \end{array} \right ] \times \left [ \begin{array} /B_{1}&B_{2}&B_{3}&\dots \end{array} \right ] = \left [ \begin{array}(A_{1}\cdot B_{1})&(A_{1}\cdot B_{2})&(A_{1}\cdot B_{3})&\dots \\(A_{2}\cdot B_{1})&(A_{2}\cdot B_{2})&(A_{2}\cdot B_{3})&\dots \\(A_{3}\cdot B_{1})&(A_{3}\cdot B_{2})&(A_{3}\cdot B_{3})&\dots \\\vdots &\vdots &\vdots &\ddots \end{array} \right ]$

### 程式實作
```cpp=
vector<vector<ll>> mat(vector<vector<ll>> &x, vector<vector<ll>> &y) {
	vector<vector<ll>> ret(p, vector<ll> (r, 0));
	for (int i = 0; i < p; i++)
		for (int j = 0; j < r; j++)
			for (int k = 0; k < q; k++)
				ret[i][j] = (ret[i][j] + x[i][k] * y[k][j]) % mod;
	return ret;
}
```
也可以用struct建矩陣，在struct裡用operator*
### 練習題
[題目](http://203.64.191.163/ShowProblem?problemid=a871)
這題不用快速冪就可以過了

## 矩陣快速冪
有可矩陣乘法的code後，矩陣快速冪就和一般的快速冪差不多了
記得要回傳的矩陣初始化時要初始化成單位矩陣
```cpp=
vector<vector<ll>> mpow(vector<vector<ll>> x, ll y) {
	vector<vector<ll>> ret = I, tmp = x;
	for (; y; y >>= 1, tmp = mat(tmp, tmp))
		if (y & 1) ret = mat(ret, tmp);
	return ret;
}
```



## 延伸學習
矩陣快速冪還可以用在DP優化上喔
[DP優化](/dvHGezXpRu-SLAj7McPc4A)