'commit'
This commit is contained in:
33
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1303.cpp
Normal file
33
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1303.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int N = 3;
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
int b[N][N] = {1, 1, 1};
|
||||
int m[N][N] = {
|
||||
{1, 0, 0},
|
||||
{1, 1, 1},
|
||||
{0, 1, 0}};
|
||||
|
||||
cin >> n >> mod;
|
||||
// 矩阵快速幂
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
printf("%d\n", b[0][0]);
|
||||
}
|
||||
136
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1303.md
Normal file
136
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1303.md
Normal file
@@ -0,0 +1,136 @@
|
||||
##[$AcWing$ $1303$. 斐波那契前 $n$ 项和](https://www.acwing.com/problem/content/1305/)
|
||||
|
||||
### 一、题目描述
|
||||
大家都知道 $Fibonacci$ 数列吧,$f_1=1,f_2=1,f_3=2,f_4=3,…,f_n=f_{n−1}+f_{n−2}$。
|
||||
|
||||
现在问题很简单,输入 $n$ 和 $m$,求 $f_n$ 的前 $n$ 项和 $S_n \ mod \ m$。
|
||||
|
||||
**输入格式**
|
||||
共一行,包含两个整数 $n$ 和 $m$。
|
||||
|
||||
**输出格式**
|
||||
输出前 $n$ 项和 $S_n\ mod\ m$ 的值。
|
||||
|
||||
**数据范围**
|
||||
$1≤n≤2000000000,1≤m≤1000000010$
|
||||
|
||||
**输入样例**:
|
||||
$5$ $1000$
|
||||
|
||||
**输出样例**:
|
||||
$12$
|
||||
|
||||
|
||||
### 二、解题思路
|
||||
普通的迭代法,是线性的,$n$的上限是$2e9$,循环的话会超时,需要想其它办法。
|
||||
|
||||
**矩阵快速幂**
|
||||
|
||||
$$\large \begin{bmatrix} s_n & f_{n+1}& f_n \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
a&b &c \\
|
||||
d&e & f \\
|
||||
h&i & j \\
|
||||
\end{bmatrix} = \begin{bmatrix} s_{n+1} & f_{n+2}& f_{n+1} \end{bmatrix}$$
|
||||
|
||||
$\therefore \\
|
||||
s_{n+1}= s_n \times a+f_{n+1} \times d+f_n \times h \\
|
||||
f_{n+2}= s_n \times b + f_{n+1} \times e + f_n \times i \\
|
||||
f_{n+1}= s_n \times c + f_{n+1} \times f + f_n \times j
|
||||
$
|
||||
|
||||
根据题目的现实含义:
|
||||
$s_{n+1}=s_n+f_{n+1}$
|
||||
$f_{n+2}=f_n+f_{n+1}$
|
||||
|
||||
推导出:
|
||||
$a=1,d=1,h=0$
|
||||
$b=0,e=1,i=1$
|
||||
$c=0,f=1,j=0$
|
||||
|
||||
整理出矩阵就是:
|
||||
$m=\begin{bmatrix}
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
0 & 1 & 0
|
||||
\end{bmatrix}$
|
||||
|
||||
已知 $s_1=1,f_2=1,f_1=1$,使用矩阵快速幂可以求解 $s_n$。
|
||||
即$b=\begin{bmatrix}
|
||||
1 & 1& 1
|
||||
\end{bmatrix}$
|
||||
|
||||
$\begin{bmatrix}s_1 & f_2 & f_1 \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
0 & 1 & 0
|
||||
\end{bmatrix} =\begin{bmatrix}s_2 & f_3 & f_2 \end{bmatrix}
|
||||
$ ①
|
||||
|
||||
$\begin{bmatrix}s_2 & f_3 & f_2 \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
0 & 1 & 0
|
||||
\end{bmatrix} =\begin{bmatrix}s_3 & f_4 & f_3 \end{bmatrix}
|
||||
$ ②
|
||||
|
||||
将 ① 代入 ② 得到:
|
||||
|
||||
$\begin{bmatrix}s_1 & f_2 & f_1 \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
0 & 1 & 0
|
||||
\end{bmatrix}^2 =\begin{bmatrix}s_3 & f_4 & f_3 \end{bmatrix}
|
||||
$
|
||||
|
||||
通过数学归纳法,得:
|
||||
|
||||
$\begin{bmatrix}s_1 & f_2 & f_1 \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
1 & 0 & 0 \\
|
||||
1 & 1 & 1 \\
|
||||
0 & 1 & 0
|
||||
\end{bmatrix}^{n-1} =\begin{bmatrix}s_n & f_{n+1} & f_n \end{bmatrix}
|
||||
$
|
||||
|
||||
|
||||
### 三、实现代码
|
||||
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int N = 3;
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
int b[N][N] = {1, 1, 1};
|
||||
int m[N][N] = {
|
||||
{1, 0, 0},
|
||||
{1, 1, 1},
|
||||
{0, 1, 0}};
|
||||
|
||||
cin >> n >> mod;
|
||||
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
printf("%d\n", b[0][0]);
|
||||
}
|
||||
```
|
||||
37
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1304.cpp
Normal file
37
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1304.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
|
||||
const int N = 4;
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
int main() {
|
||||
int b[N][N] = {1, 1, 1, 0};
|
||||
int m[N][N] = {
|
||||
{1, 1, 1, 0},
|
||||
{1, 0, 0, 0},
|
||||
{0, 0, 1, 1},
|
||||
{0, 0, 0, 1}};
|
||||
|
||||
cin >> n >> mod;
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
int t = (n * b[0][2]) - b[0][3];
|
||||
t = (t % mod + mod) % mod;
|
||||
printf("%lld\n", t);
|
||||
return 0;
|
||||
}
|
||||
144
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1304.md
Normal file
144
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1304.md
Normal file
@@ -0,0 +1,144 @@
|
||||
##[$AcWing$ $1304$. 佳佳的斐波那契](https://www.acwing.com/problem/content/1306/)
|
||||
### 一、题目描述
|
||||
佳佳对数学,尤其对数列十分感兴趣。
|
||||
|
||||
在研究完 $Fibonacci$ 数列后,她创造出许多稀奇古怪的数列。
|
||||
|
||||
例如用 $S(n)$ 表示 $Fibonacci$ 前 $n$ 项和 $mod\ m$ 的值,即 $S(n)=(F_1+F_2+…+F_n)\ mod\ m$,其中 $F_1=F_2=1,F_i=F_{i−1}+F_{i−2}$。
|
||||
|
||||
可这对佳佳来说还是小菜一碟。
|
||||
|
||||
终于,她找到了一个自己解决不了的问题。
|
||||
|
||||
用 $T(n)=(F_1+2F_2+3F_3+…+nF_n)\ mod\ m$ 表示 $Fibonacci$ 数列前 $n$ 项变形后的和 $mod\ m$ 的值。
|
||||
|
||||
现在佳佳告诉你了一个 $n$ 和 $m$,请求出 $T(n)$ 的值。
|
||||
|
||||
**输入格式**
|
||||
共一行,包含两个整数 $n$ 和 $m$。
|
||||
|
||||
**输出格式**
|
||||
共一行,输出 $T(n)$ 的值。
|
||||
|
||||
**数据范围**
|
||||
$1≤n,m≤2^{31}−1$
|
||||
|
||||
**输入样例**:
|
||||
$5$ $5$
|
||||
|
||||
**输出样例**:
|
||||
$1$
|
||||
|
||||
**样例解释**
|
||||
$T(5)=(1+2×1+3×2+4×3+5×5)\ mod\ 5=1$
|
||||
|
||||
### 二、推导过程
|
||||
$$\because S_n=F_1+F_2+⋯+F_n=\sum_{i=1}^{n}F_i \\
|
||||
T_n=F_1+2*F_2+...+nF_n=\sum_{i=1}^{n}iF_i$$
|
||||
|
||||
我们需要利用$T_n$构造新的数列,从而消去变量$i$,最后再反解出$T_n$:
|
||||
|
||||
$$\therefore nS_n-T_n=(n-1)F_1+(n-2)F_2+...+F_{n-1}$$
|
||||
令$C_n=nS_n-T_n$
|
||||
|
||||
$$\therefore C_n=(n-1)F_1+(n-2)F_2+...+F_{n-1} \ ①$$
|
||||
$$C_{n+1}=nF_1+(n-1)F_2+...+F_{n} \ ② $$
|
||||
|
||||
② 式 - ① 式
|
||||
|
||||
$$C_{n+1}-C_n=F_1+F_2+F_3+...+F_n=S_n$$
|
||||
|
||||
于是我们只需维护如下矩阵即可
|
||||
$$
|
||||
\begin{pmatrix}
|
||||
f_{n+1} & f_n & s_n & c_n
|
||||
\end{pmatrix}
|
||||
$$
|
||||
|
||||
有如下等式:
|
||||
$$
|
||||
\begin{pmatrix}
|
||||
f_{n+1} & f_n & s_n & c_n
|
||||
\end{pmatrix} \times
|
||||
\begin{pmatrix}
|
||||
1 & 1 & 1 & 0 \\
|
||||
1 & 0 & 0 & 0 \\
|
||||
0 & 0 & 1 & 1 \\
|
||||
0 & 0 & 0 & 1
|
||||
\end{pmatrix}=
|
||||
\begin{pmatrix}
|
||||
f_{n+2} & f_{n+1} & s_{n+1} & c_{n+1}
|
||||
\end{pmatrix}
|
||||
$$
|
||||
|
||||
然后直接使用矩阵快速幂便可以求解
|
||||
|
||||
|
||||
|
||||
**初始矩阵**
|
||||
$$\begin{pmatrix}
|
||||
f_{2} & f_{1} & s_{1} & c_{1} \\
|
||||
\end{pmatrix} =
|
||||
\begin{pmatrix}
|
||||
1 & 1 & 1 & 0
|
||||
\end{pmatrix}
|
||||
$$
|
||||
|
||||
**递推式**
|
||||
$$\begin{pmatrix}
|
||||
f_{n+1} & f_{n} & s_{n} & c_{n} \\
|
||||
\end{pmatrix} =\begin{pmatrix}
|
||||
f_{2} & f_{1} & s_{1} & c_{1} \\
|
||||
\end{pmatrix} \times
|
||||
\begin{pmatrix}
|
||||
1 & 1 & 1 & 0 \\
|
||||
1 & 0 & 0 & 0 \\
|
||||
0 & 0 & 1 & 1 \\
|
||||
0 & 0 & 0 & 1
|
||||
\end{pmatrix}^{n-1}
|
||||
$$
|
||||
|
||||
**答案**
|
||||
$T_n=nS_n-C_n =n\times b[0][2]-b[0][3]$
|
||||
|
||||
### $Code$
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
|
||||
const int N = 4;
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
int main() {
|
||||
int b[N][N] = {1, 1, 1, 0};
|
||||
int m[N][N] = {
|
||||
{1, 1, 1, 0},
|
||||
{1, 0, 0, 0},
|
||||
{0, 0, 1, 1},
|
||||
{0, 0, 0, 1}};
|
||||
|
||||
cin >> n >> mod;
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
int t = (n * b[0][2]) - b[0][3];
|
||||
t = (t % mod + mod) % mod;
|
||||
printf("%lld\n", t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
218
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305.md
Normal file
218
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305.md
Normal file
@@ -0,0 +1,218 @@
|
||||
##[$AcWing$ $1305$. $GT$考试](https://www.acwing.com/problem/content/description/1307/)
|
||||
|
||||
[洛谷链接](https://www.luogu.com.cn/problem/P3193)
|
||||
|
||||
### 一、题目描述
|
||||
阿申准备报名参加 $GT$ 考试,准考证号为 $n$ 位数 $X_1X_2⋯X_n$,他不希望准考证号上出现不吉利的数字。
|
||||
|
||||
他的不吉利数字 $A_1A_2⋯A_m$ 有 $m$ 位,不出现是指 $X_1X_2⋯X_n$ 中没有恰好一段等于 $A_1A_2⋯A_m$,$A_1$ 和 $X_1$ 可以为 $0$。
|
||||
|
||||
**输入格式**
|
||||
第一行输入 $n,m,K$。
|
||||
|
||||
接下来一行输入 $m$ 位的不吉利数字。
|
||||
|
||||
**输出格式**
|
||||
阿申想知道不出现不吉利数字的号码有多少种,输出模 $K$ 取余的结果。
|
||||
|
||||
**数据范围**
|
||||
$0≤X_i,A_i≤9,1≤n≤10^9,1≤m≤20,2≤K≤1000$
|
||||
|
||||
**输入样例:**
|
||||
```cpp {.line-numbers}
|
||||
4 3 100
|
||||
111
|
||||
```
|
||||
**输出样例:**
|
||||
```cpp {.line-numbers}
|
||||
81
|
||||
```
|
||||
### 二、前导知识
|
||||
**母题**:[$AcWing$ $1052$. 设计密码](https://www.acwing.com/problem/content/1054/)
|
||||
|
||||
- **扩展方式$1$**:**数据量扩展**
|
||||
$AcWing$ $1052$. 设计密码中的$n$值最大为$50$,本题的$n$最大可以取到$10^9$。
|
||||
<br>
|
||||
- **扩展方式$2$: 不能包含多个字符串**
|
||||
对应题目是:[$AcWing$ $1053$. 修复$DNA$](https://www.acwing.com/problem/content/1055/),可以使用$AC$自动机解决。
|
||||
|
||||
### 三、暴力$dp$
|
||||
利用$kmp$算法求方案数
|
||||
|
||||
- **状态表示**
|
||||
设$f[i][j]$表示$dp$到长串的第$i$位,匹配了短串的前缀长度为$j$时的 **总方案数**
|
||||
|
||||
**答案**: $\displaystyle \sum_{j=0}^{m-1}f[n][j]$
|
||||
|
||||
- **状态转移**
|
||||
枚举$0 \sim 9$的每一个数,看在匹配 **不能出现的串** $j$位后 **再加当前枚举的数能变成匹配几位**,如果匹配$m$位了则不合法:
|
||||
* 如果新加的这一位 **可以** 与 **不能出现的串** 的下一位匹配,那么就可以转移到 $f[i + 1][j + 1]$。
|
||||
* 如果新加的这一位 **不能** 与 **不能出现的串** 的下一位匹配,就往回找第一个能匹配的位置,利用$kmp$的$ne$数组往回跳,匹配一个新的前缀。假设找到的位置$u=ne[u]+1$,那么当前状态就可以转移到$f[i+1][u]$。
|
||||
|
||||
**$40$分代码**
|
||||
复杂度$O(nm^2)$直接爆炸
|
||||
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
typedef long long LL;
|
||||
int n, m, mod;
|
||||
const int N = 1e6 + 10;
|
||||
int ne[N]; // kmp的ne数组,针对模式串s
|
||||
char s[N]; // 模式串s
|
||||
int f[N][22]; // dp数组
|
||||
|
||||
//原始版本,就是设计密码那道题的代码,可以过4个点,剩余6个点TLE
|
||||
int main() {
|
||||
cin >> n >> m >> mod;
|
||||
cin >> s + 1;
|
||||
// kmp
|
||||
for (int i = 2, j = 0; i <= m; i++) {
|
||||
while (j && s[j + 1] != s[i]) j = ne[j];
|
||||
if (s[j + 1] == s[i]) j++;
|
||||
ne[i] = j;
|
||||
}
|
||||
|
||||
//普通dp
|
||||
f[0][0] = 1;
|
||||
for (int k = 0; k < n; k++)
|
||||
for (int i = 0; i < m; i++)
|
||||
for (char c = '0'; c <= '9'; c++) {
|
||||
int j = i;
|
||||
while (j && s[j + 1] != c) j = ne[j];
|
||||
if (s[j + 1] == c) j++;
|
||||
//在kmp过程中进行判断,不能命中m个长度,需要避让
|
||||
if (j < m) f[k + 1][j] = (f[k + 1][j] + f[k][i]) % mod;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < m; i++) res = (res + f[n][i]) % mod;
|
||||
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 四、矩阵优化
|
||||
|
||||
时间复杂度$O(m^3logn)$
|
||||
|
||||
设计密码那道题的$n<=20$,这道题的数据范围有$1e9$!
|
||||
看到这个令人发指的数量级,感觉到普通$dp$肯定凉凉,一定要用特殊手段!
|
||||
|
||||
<center><img src='https://cdn.acwing.com/media/article/image/2021/04/20/61813_4df7b95da1-image-20210420111924845.png'></center>
|
||||
|
||||
通过上面的分析,我们根据状态计算可以得到第$i$层和第$i+1$层之间的关系,即
|
||||
|
||||
$\large \left\{\begin{array}{ll}
|
||||
f[i+1][0]=f[i][0] * a[0][0] + f[i][1] * a[1][0]+...+f[i][m-1] * a[m-1][0] & \\
|
||||
f[i+1][1]=f[i][0] * a[0][1] + f[i][1] * a[1][1]+...+f[i][m-1] * a[m-1][1] & \\
|
||||
... & \\
|
||||
f[i+1][m-1]=f[i][0] * a[0][m-1] + f[i][1] * a[1][m-1]+...+f[i][m-1] * a[m-1][m-1]
|
||||
\end{array}\right.
|
||||
$
|
||||
|
||||
看着像矩阵,构造一下,令: $$\large F[i+1]=(f[i+1][0],f[i+1][1],...,f[i+1][m-1])$$
|
||||
|
||||
$$
|
||||
\large A= \begin{bmatrix}
|
||||
a_{0,0}& a_{0,1} & ... & a_{0,m-1} \\
|
||||
a_{1,0}& a_{1,1} & ... & a_{1,m-1} \\
|
||||
... \\
|
||||
a_{m-1,0}& a_{m-1,1} & ... & a_{m-1,m-1}
|
||||
\end{bmatrix}
|
||||
$$
|
||||
|
||||
**递推式**:
|
||||
$$\large F(i+1)=F(i)*A$$
|
||||
|
||||
**证明**:
|
||||
$$\large
|
||||
\begin{bmatrix}
|
||||
f(i+1,0),f(i+1,1),...,f(i+1,m-1)
|
||||
\end{bmatrix} = \\
|
||||
\begin{bmatrix}
|
||||
f(i,0),f(i,1),...,f(i,m-1)
|
||||
\end{bmatrix}
|
||||
\times
|
||||
\begin{bmatrix}
|
||||
a_{0,0}& a_{0,1} & ... & a_{0,m-1} \\
|
||||
a_{1,0}& a_{1,1} & ... & a_{1,m-1} \\
|
||||
... \\
|
||||
a_{m-1,0}& a_{m-1,1} & ... & a_{m-1,m-1}
|
||||
\end{bmatrix}$$
|
||||
|
||||
<font color='red' size=4><b>结论:具有递推性质!</b></font>
|
||||
|
||||
#### $Q1:A$矩阵实际含义
|
||||
答:$A[k][j]$ 表示在 **和短串匹配长度为$k$的串(后缀)** 后面添加一个字符,使新构成的串 **和短串匹配长度为$j$(前缀)**,这样的字符添加方案数。
|
||||
|
||||
#### $Q2:$$A$矩阵求法
|
||||
答:根据上面的分析可知,矩阵$A$只与不合法串$S$有关,因此$A$矩阵是不变的。根据上面递推式可知:
|
||||
$$\large F(n)=F(0)×A^n \ , \ F[0][0]={1}$$
|
||||
|
||||
如何求解数组$A$呢?如果从$f(i, j)$可以转移到$f(i+1, k)$,则让$a[j, k]++$。即让$f(i+1, k) += f(i, j)$:
|
||||
<center><img src='https://cdn.acwing.com/media/article/image/2021/04/20/61813_63cbabd3a1-image-20210420120151532.png'></center>
|
||||
|
||||
求出向量$F(n)$后,最后的答案就是向量$F(n)$中所有的元素之和。
|
||||
|
||||
#### 总结
|
||||
对于所有类似于本题的$DP$问题(状态转移方程是线性的)都可以采用快速幂的优化方式
|
||||
|
||||
**$AC$代码**
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
typedef long long LL;
|
||||
const int N = 25;
|
||||
|
||||
int n, m, mod;
|
||||
char s[N];
|
||||
int ne[N];
|
||||
int a[N][N];
|
||||
|
||||
//矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (LL)(a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n >> m >> mod;
|
||||
cin >> s + 1;
|
||||
|
||||
// kmp
|
||||
for (int i = 2, j = 0; i <= m; i++) {
|
||||
while (j && s[j + 1] != s[i]) j = ne[j];
|
||||
if (s[j + 1] == s[i]) j++;
|
||||
ne[i] = j;
|
||||
}
|
||||
|
||||
// 初始化A[i][j]
|
||||
for (int i = 0; i < m; i++)
|
||||
for (int c = '0'; c <= '9'; c++) {
|
||||
int j = i;
|
||||
while (j && s[j + 1] != c) j = ne[j];
|
||||
if (s[j + 1] == c) j++;
|
||||
if (j < m) a[i][j]++;
|
||||
}
|
||||
|
||||
// f[0][0]=1 base case
|
||||
int f[N][N] = {1};
|
||||
//矩阵快速幂
|
||||
for (int i = n; i; i >>= 1) {
|
||||
if (i & 1) mul(f, a, f); // f:基底 a:需要计算快速幂的常数矩阵 f:结果存储
|
||||
mul(a, a, a); //倍增a
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < m; i++) res = (res + f[0][i]) % mod;
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
38
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305_BF_DP.cpp
Normal file
38
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305_BF_DP.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
typedef long long LL;
|
||||
int n, m, mod;
|
||||
const int N = 1e6 + 10;
|
||||
int ne[N]; // kmp的ne数组,针对模式串s
|
||||
char s[N]; // 模式串s
|
||||
int f[N][22]; // dp数组
|
||||
|
||||
//原始版本,就是设计密码那道题的代码,可以过4个点,剩余6个点TLE
|
||||
int main() {
|
||||
cin >> n >> m >> mod;
|
||||
cin >> s + 1;
|
||||
// kmp
|
||||
for (int i = 2, j = 0; i <= m; i++) {
|
||||
while (j && s[j + 1] != s[i]) j = ne[j];
|
||||
if (s[j + 1] == s[i]) j++;
|
||||
ne[i] = j;
|
||||
}
|
||||
|
||||
//普通dp
|
||||
f[0][0] = 1;
|
||||
for (int k = 0; k < n; k++)
|
||||
for (int i = 0; i < m; i++)
|
||||
for (char c = '0'; c <= '9'; c++) {
|
||||
int j = i;
|
||||
while (j && s[j + 1] != c) j = ne[j];
|
||||
if (s[j + 1] == c) j++;
|
||||
//在kmp过程中进行判断,不能命中m个长度,需要避让
|
||||
if (j < m) f[k + 1][j] = (f[k + 1][j] + f[k][i]) % mod;
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < m; i++) res = (res + f[n][i]) % mod;
|
||||
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
54
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305_JZ_DP.cpp
Normal file
54
TangDou/AcWing_TiGao/T5/JuZhengChengFa/1305_JZ_DP.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
typedef long long LL;
|
||||
const int N = 25;
|
||||
|
||||
int n, m, mod;
|
||||
char s[N];
|
||||
int ne[N];
|
||||
int a[N][N];
|
||||
|
||||
//矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (LL)(a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n >> m >> mod;
|
||||
cin >> s + 1;
|
||||
|
||||
// kmp
|
||||
for (int i = 2, j = 0; i <= m; i++) {
|
||||
while (j && s[j + 1] != s[i]) j = ne[j];
|
||||
if (s[j + 1] == s[i]) j++;
|
||||
ne[i] = j;
|
||||
}
|
||||
|
||||
// 初始化A[i][j]
|
||||
for (int i = 0; i < m; i++)
|
||||
for (int c = '0'; c <= '9'; c++) {
|
||||
int j = i;
|
||||
while (j && s[j + 1] != c) j = ne[j];
|
||||
if (s[j + 1] == c) j++;
|
||||
if (j < m) a[i][j]++;
|
||||
}
|
||||
|
||||
// f[0][0]=1 base case
|
||||
int f[N][N] = {1};
|
||||
//矩阵快速幂
|
||||
for (int i = n; i; i >>= 1) {
|
||||
if (i & 1) mul(f, a, f); // f:基底 a:需要计算快速幂的常数矩阵 f:结果存储
|
||||
mul(a, a, a); //倍增a
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
for (int i = 0; i < m; i++) res = (res + f[0][i]) % mod;
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
52
TangDou/AcWing_TiGao/T5/JuZhengChengFa/B2105.cpp
Normal file
52
TangDou/AcWing_TiGao/T5/JuZhengChengFa/B2105.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int N = 110;
|
||||
int n, m, k;
|
||||
int a[N][N], b[N][N], c[N][N];
|
||||
|
||||
// 矩阵乘法模板
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
// 注意:这里的临时数组t绝不是画蛇添足!
|
||||
// 因为调用的时候,有时会传递mul(a,b,b)这样的东东,如果每次memset(c,0,sizeof c),
|
||||
// 就会造成b在运行前被清空,导致结果错误
|
||||
|
||||
// 代码解释:
|
||||
// 从结果出发理解:
|
||||
// C(i,j) =A(i,1)×B(1,j)+A(i,2)×B(2,j) +...A(r,1)×B(r,j)
|
||||
// 抽象一下:
|
||||
// C(i,j) = C(i,j) + A(i,k)× B(k,j)
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = t[i][j] + a[i][k] * b[k][j]; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
int main() {
|
||||
#ifndef ONLINE_JUDGE
|
||||
freopen("B2105.in", "r", stdin);
|
||||
#endif
|
||||
cin >> n >> m >> k;
|
||||
|
||||
// A矩阵 n*m
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int j = 1; j <= m; j++)
|
||||
cin >> a[i][j];
|
||||
|
||||
// B矩阵m*k
|
||||
for (int i = 1; i <= m; i++)
|
||||
for (int j = 1; j <= k; j++)
|
||||
cin >> b[i][j];
|
||||
|
||||
// 矩阵乘法
|
||||
mul(a, b, c);
|
||||
|
||||
// 输出结果,控制格式
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= k; j++)
|
||||
printf("%d ", c[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
6
TangDou/AcWing_TiGao/T5/JuZhengChengFa/B2105.in
Normal file
6
TangDou/AcWing_TiGao/T5/JuZhengChengFa/B2105.in
Normal file
@@ -0,0 +1,6 @@
|
||||
3 2 3
|
||||
1 1
|
||||
1 1
|
||||
1 1
|
||||
1 1 1
|
||||
1 1 1
|
||||
42
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.cpp
Normal file
42
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 4;
|
||||
int n;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j] % MOD)) % MOD;
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
void solve() {
|
||||
int b[N][N] = {1, 1, 1}, m[N][N] = {0};
|
||||
m[0][2] = m[1][0] = m[2][1] = m[2][2] = 1;
|
||||
|
||||
for (int i = n - 3; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
printf("%lld\n", b[0][2]);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
int T;
|
||||
cin >> T;
|
||||
while (T--) {
|
||||
cin >> n;
|
||||
if (n <= 3) {
|
||||
printf("1\n");
|
||||
continue;
|
||||
}
|
||||
solve();
|
||||
}
|
||||
}
|
||||
1
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.drawio
Normal file
1
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2022-11-01T06:55:20.054Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.3.0 Chrome/104.0.5112.114 Electron/20.1.3 Safari/537.36" etag="ZX1vPpEdbHFyJT1jah8Q" version="20.3.0" type="device"><diagram id="kiFii2xGKzMq8TPXHEmb" name="第 1 页">5Zxdk5owFIZ/DZfbAQJEb9W120570dqZzvSOlShMwTAYV+2vb1yDSs6sbWfWnhzWG+CErzzwnjmviXpsXO3eN2mdf5aZKL3Qz3Yem3hhGASDUC8Okf0xMojiY2DZFJnZ6RyYFb+ECfomuikyse7sqKQsVVF3g3O5Wom56sTSppHb7m4LWXavWqdLAQKzeVrC6PciU7npRcjP8QdRLPP2ykEyPLZUabuz6ck6TzO5vQixe4+NGynVca3ajUV5gNdyOR43faH1dGONWKm/OaCqq2+fHr5spl+jyYd6s/7x8Sm4M2d5SsuN6fDCi0eBF0/0ojgsjveu9i2QRm5WmTic0/fYaJsXSszqdH5o3epXQMdyVZV6K9CrC7lS5pkeOjxaFGU5lqVsns/FGJvqj46vVSN/iouWZD4QjwvdYu5PNErsXux4cMKp30MhK6Gavd7FHBAPzRPYt8/IbG/PD5SbUH7xLBMTS80rtDyd+UxZrxjQ/wA9vAr9LugH9iRxDDu7jj3sB3bOHMMeAew3pTydGsq3yBwcmWVMlyVIB9gsE7osgcaxWXK6LG2NhwyZ5YAuS1vj6CyHdFnaGkdn2dYRPS9bXSufgusWrS9la+C7xv0PLo31hDt3jTu0aWRytmtlWUDYe4GEgA6TsPkCKkeHSdh9OVeYEXZftsrxYRK2X7bK0WEy6L+Cm9P0/deS+eBd3M2a2LVRBC0YIZ7cPZ7QW/lkeEaRezyhZ6LDU+u9SxO7RoqgEyJEk7tGE3ohOrlTa90xmtAM0aFpKx29ToqgG6KrdHya0A/RoWkrHZ8mNER9/P45Hgw73CMfmzv0Tn0cbklix7jH14e5+kGdh65Rh07s5in71WYQ2KkjwYYJbRgZmCAfoMMkPB4FZI4Ok/CAlC3zOMSGSXhAypY5PkzCA1K2zPFhQgfWx7kTzhVRb8OqDV3D/jac2umXTa5wT6BTI5OyXSvMEsL+y84H6CwJ2y8gcnSYhO2Xa2VZQth9DV1jSdh82SLHh0l6/Mvn1jwM/MqI8ggY4+7xhMaKzmh3FLnHk/a8QN6liV0itRejqnbHaNKeE+gaTeiF6NC0lY5eJ3FohgjlTe4aTdozAv8bTb15/pei57aL/3pi978B</diagram></mxfile>
|
||||
98
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.md
Normal file
98
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P1939.md
Normal file
@@ -0,0 +1,98 @@
|
||||
## [$P1939$ 【模板】矩阵加速(数列)](https://www.luogu.com.cn/problem/P1939)
|
||||
|
||||
|
||||
### 一、题目描述
|
||||

|
||||
|
||||
|
||||
### 二、解题思路
|
||||
从题目上来看,知道需要递推求公式,但$n<=2e9$,我们知道简单递推肯定要挂掉。
|
||||
|
||||
所以想到需要一个$O(NlogN)$的算法,递推求式子,线性的还不行,联想到矩阵快速幂。
|
||||
|
||||
$$\large \begin{bmatrix}f_{x-3} & f_{x-2} & f_{x-1} \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
a&b &c \\
|
||||
d&e &f \\
|
||||
g&h &i
|
||||
\end{bmatrix} = \begin{bmatrix}f_{x-2} & f_{x-1} & f_{x} \end{bmatrix}
|
||||
$$
|
||||
|
||||
$\therefore$
|
||||
$\large f_{x-3} \times a+f_{x-2}\times d + f_{x-1}\times g =f_{x-2}$
|
||||
$\large f_{x-3} \times b+f_{x-2}\times e + f_{x-1}\times h =f_{x-1}$
|
||||
$\large f_{x-3} \times c+f_{x-2}\times f + f_{x-1}\times i =f_{x}$
|
||||
|
||||
对比观察得到:
|
||||
$a=0,d=1,g=0$
|
||||
$b=0,e=0,h=1$
|
||||
$c=1,f=0,i=1$
|
||||
|
||||
得到
|
||||
$$m=\begin{bmatrix}
|
||||
0& 0 & 1 \\
|
||||
1& 0 & 0 \\
|
||||
0& 1 & 1
|
||||
\end{bmatrix}$$
|
||||
|
||||
而初始化矩阵$b=\begin{bmatrix} f_{1}& f_{2} & f_3 \end{bmatrix}=\begin{bmatrix} 1&1&1 \end{bmatrix}$
|
||||
|
||||
**递推式**:
|
||||
$\large b=\begin{bmatrix}f_{x-2}& f_{x-1} & f_x \end{bmatrix}=
|
||||
\begin{bmatrix}f_{1}& f_{2} & f_3 \end{bmatrix} \times
|
||||
\begin{bmatrix}
|
||||
0& 0 & 1 \\
|
||||
1& 0 & 0 \\
|
||||
0& 1 & 1
|
||||
\end{bmatrix}^{n-3}
|
||||
$
|
||||
|
||||
**答案**:
|
||||
$\large b[0][2]$
|
||||
|
||||
$Code$
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 4;
|
||||
int n;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j] % MOD)) % MOD;
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
void solve() {
|
||||
int b[N][N] = {1, 1, 1}, m[N][N] = {0};
|
||||
m[0][2] = m[1][0] = m[2][1] = m[2][2] = 1;
|
||||
|
||||
for (int i = n - 3; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
printf("%lld\n", b[0][2]);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
int T;
|
||||
cin >> T;
|
||||
while (T--) {
|
||||
cin >> n;
|
||||
if (n <= 3) {
|
||||
printf("1\n");
|
||||
continue;
|
||||
}
|
||||
solve();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
31
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3193_BF.cpp
Normal file
31
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3193_BF.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
int n, m, k;
|
||||
string s;
|
||||
int res;
|
||||
/*
|
||||
4 3 100
|
||||
111
|
||||
|
||||
答案:81
|
||||
*/
|
||||
void dfs(int u, string t) {
|
||||
if (u == n) {
|
||||
if (t.find(s) == string::npos) res++;
|
||||
res = res % k;
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i <= 9; i++) {
|
||||
t.push_back(i + '0');
|
||||
dfs(u + 1, t);
|
||||
t.pop_back();
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
cin >> n >> m >> k;
|
||||
cin >> s;
|
||||
dfs(0, "");
|
||||
printf("%d\n", res);
|
||||
return 0;
|
||||
}
|
||||
42
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3390_1.cpp
Normal file
42
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3390_1.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 110;
|
||||
int n, k; // 本题数据范围很大,用int直接wa哭了
|
||||
int a[N][N], b[N][N]; // 原始矩阵,结果矩阵
|
||||
|
||||
// 矩阵乘法模板
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
cin >> n >> k;
|
||||
// 输入原始矩阵
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < n; j++)
|
||||
cin >> a[i][j];
|
||||
|
||||
// 1、单位矩阵
|
||||
for (int i = 0; i < n; i++) b[i][i] = 1;
|
||||
|
||||
// 2、矩阵快速幂
|
||||
for (int i = k; i; i >>= 1) {
|
||||
if (i & 1) mul(a, b, b);
|
||||
mul(a, a, a);
|
||||
}
|
||||
|
||||
// 3、输出
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%lld ", b[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
44
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3390_2.cpp
Normal file
44
TangDou/AcWing_TiGao/T5/JuZhengChengFa/P3390_2.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 110;
|
||||
int n, k; // 本题数据范围很大,用int直接wa哭了
|
||||
int a[N][N], b[N][N]; // 原始矩阵,结果矩阵
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n >> k;
|
||||
// 1、输入原始矩阵
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < n; j++) {
|
||||
cin >> a[i][j];
|
||||
b[i][j] = a[i][j]; // 这种解法与标准解法不同,不用构建单位矩阵
|
||||
// 直接赋值初始化了一个,然后执行k-1次就完成了矩阵的k次幂
|
||||
}
|
||||
|
||||
// 2、计算矩阵快速幂
|
||||
for (int i = k - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(a, b, b);
|
||||
mul(a, a, a);
|
||||
}
|
||||
|
||||
// 3、输出
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%lld ", b[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
45
TangDou/AcWing_TiGao/T5/JuZhengChengFa/YBT_1641.cpp
Normal file
45
TangDou/AcWing_TiGao/T5/JuZhengChengFa/YBT_1641.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int N = 110;
|
||||
int n, m, k;
|
||||
int a[N][N], b[N][N], c[N][N];
|
||||
|
||||
// 用户名:littlehb 密码:md******22
|
||||
|
||||
// 矩阵乘法模板
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
// 注意:这里的临时数组t绝不是画蛇添足!
|
||||
// 因为调用的时候,有时会传递mul(a,b,b)这样的东东,如果每次memset(c,0,sizeof c),
|
||||
// 就会造成b在运行前被清空,导致结果错误
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = t[i][j] + a[i][k] * b[k][j]; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
int main() {
|
||||
cin >> n >> m;
|
||||
// A矩阵 n*m
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int j = 1; j <= m; j++)
|
||||
cin >> a[i][j];
|
||||
|
||||
// B矩阵m*k
|
||||
cin >> k;
|
||||
for (int i = 1; i <= m; i++)
|
||||
for (int j = 1; j <= k; j++)
|
||||
cin >> b[i][j];
|
||||
|
||||
// 矩阵乘法
|
||||
mul(a, b, c);
|
||||
|
||||
// 输出结果,控制格式
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= k; j++)
|
||||
printf("%d ", c[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
48
TangDou/AcWing_TiGao/T5/JuZhengChengFa/YBT_1642.cpp
Normal file
48
TangDou/AcWing_TiGao/T5/JuZhengChengFa/YBT_1642.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
const int INF = 0x3f3f3f3f;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
/*
|
||||
http://ybt.ssoier.cn:8088/problem_show.php?pid=1642
|
||||
测试用例:
|
||||
5 1000
|
||||
|
||||
答案:
|
||||
5
|
||||
*/
|
||||
const int N = 2;
|
||||
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
cin >> n >> mod;
|
||||
|
||||
int b[N][N] = {1, 1}; // 结果矩阵(初始化fib[2]=1,fib[1]=1)
|
||||
|
||||
// 构造的向量数组
|
||||
int m[N][N] = {
|
||||
{1, 1},
|
||||
{1, 0}};
|
||||
|
||||
// 矩阵快速幂
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
printf("%lld\n", b[0][1]);
|
||||
return 0;
|
||||
}
|
||||
427
TangDou/AcWing_TiGao/T5/JuZhengChengFa/矩阵乘法与矩阵快速幂.md
Normal file
427
TangDou/AcWing_TiGao/T5/JuZhengChengFa/矩阵乘法与矩阵快速幂.md
Normal file
@@ -0,0 +1,427 @@
|
||||
## 矩阵乘法与矩阵快速幂
|
||||
|
||||
### 一、矩阵的定义
|
||||
|
||||
一个 $m\times n$ 的矩阵就是 $m$ 行 $n$ 列的数字阵列,如$2 \times 3$的矩阵:$\begin{bmatrix}
|
||||
1 & 5 & 3 \\
|
||||
2 & 8 & 10
|
||||
\end{bmatrix}$
|
||||
|
||||
实际上,**矩阵类似二维数组**。
|
||||
|
||||
### 2. 矩阵的运算
|
||||
- **矩阵的加法和减法**
|
||||
矩阵的加法和减法就是将两个矩阵对应位置上的数相加减。因此,相加减的两个矩阵$A$,$B$的行列必须相同。
|
||||
|
||||
- **矩阵乘法**
|
||||
$A$,$B$,$C$ 是三个矩阵,若 $A\times B=C$,需要满足:
|
||||
|
||||
- $A$ 的列数必须和 $B$ 的行数相等;
|
||||
- 设 $A$ 是一个 $n\times r$ 的矩阵,$B$ 是一个 $r\times m$ 的矩阵,则矩阵 $A$ 乘 矩阵 $B$ 的乘积 $C$ 是一个 $n\times m$ 的矩阵;
|
||||
- $C_{(i,j)} =A_{(i,1)} ×B_{(1,j)} +A_{(i,2)}×B_{(2,j)} +...A_{(r,1)} ×B_{(r,j)}$
|
||||
|
||||
矩阵 $C$ 的第 $i$ 行第 $j$ 列元素 = 矩阵 $A$ 的第 $i$ 行元素与矩阵 $B$的第 $j$ 列对应元素乘积之和。
|
||||
|
||||
例如:$A= \begin{bmatrix}
|
||||
a & b \\
|
||||
c & d \\
|
||||
e & f
|
||||
\end{bmatrix},
|
||||
B= \begin{bmatrix}
|
||||
g & h & i \\
|
||||
j & k & l
|
||||
\end{bmatrix}$,求$C=A \times B$
|
||||
|
||||
$A \times B=\begin{bmatrix}
|
||||
a \times g+b \times j & a \times h+b \times k & a \times i + b \times l \\
|
||||
c \times g+d \times j & c \times h+d \times k & c \times i + d \times l \\
|
||||
e \times g+f \times j & e \times h+f \times k & e \times i + f \times l
|
||||
\end{bmatrix}$
|
||||
|
||||
可以发现 $A\times B$ 和 $B\times A$ 将得到两种不同的结果,因此矩阵不满足乘法交换律。
|
||||
|
||||
- **方阵次幂**
|
||||
如果矩阵的行和列相同,称矩阵为方阵。若 $A$ 是一个方阵,方阵的幂是指,将 $A$ 连乘 $n$ 次,$A^n$。
|
||||
|
||||
若不是方阵则无法进行乘幂运算。
|
||||
|
||||
**矩阵乘法不满足交换律,但是满足结合律,因此可以用快速幂的思想来求解方程次幂**。
|
||||
|
||||
### 3. 矩阵乘法的应用
|
||||
在信息学竞赛中考矩阵乘法不是为了考基本运算,而是利用矩阵乘法的特性,配合快速幂求解递推式的第 $n$ 项,以及一些图论的构造转化。
|
||||
|
||||
**[一本通 $1641$ 矩阵乘法](http://ybt.ssoier.cn:8088/problem_show.php?pid=1641)**
|
||||
|
||||
**[$B2105$ 矩阵乘法](https://www.luogu.com.cn/problem/B2105)**
|
||||
|
||||
> **注释**:上面两道题其实是一样的模板,只不过输入的数据顺序不太一样。
|
||||
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
const int N = 110;
|
||||
int n, m, k;
|
||||
int a[N][N], b[N][N], c[N][N];
|
||||
|
||||
// 矩阵乘法模板
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
// 注意:这里的临时数组t绝不是画蛇添足!
|
||||
// 因为调用的时候,有时会传递mul(a,b,b)这样的东东,如果每次memset(c,0,sizeof c),
|
||||
// 就会造成b在运行前被清空,导致结果错误
|
||||
|
||||
// 代码解释:
|
||||
// 从结果出发理解:
|
||||
// C(i,j) =A(i,1)×B(1,j)+A(i,2)×B(2,j) +...A(r,1)×B(r,j)
|
||||
// 抽象一下:
|
||||
// C(i,j) = C(i,j) + A(i,k)× B(k,j)
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = t[i][j] + a[i][k] * b[k][j]; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
int main() {
|
||||
cin >> n >> m >> k;
|
||||
|
||||
// A矩阵 n*m
|
||||
for (int i = 1; i <= n; i++)
|
||||
for (int j = 1; j <= m; j++)
|
||||
cin >> a[i][j];
|
||||
|
||||
// B矩阵m*k
|
||||
for (int i = 1; i <= m; i++)
|
||||
for (int j = 1; j <= k; j++)
|
||||
cin >> b[i][j];
|
||||
|
||||
// 矩阵乘法
|
||||
mul(a, b, c);
|
||||
|
||||
// 输出结果,控制格式
|
||||
for (int i = 1; i <= n; i++) {
|
||||
for (int j = 1; j <= k; j++)
|
||||
printf("%d ", c[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**[$P3390$ 【模板】矩阵快速幂](https://www.luogu.com.cn/problem/P3390)**
|
||||
|
||||
- **快速幂**
|
||||
实现 $pow(x, n)$ ,即计算 $x$ 的整数 $n$ 次幂函数 (即$x^n$)。
|
||||
|
||||
对于上面这道题,我们最容易想到的解法就是通过循环或递归进行累乘求解
|
||||
```cpp {.line-numbers}
|
||||
public double MyPow(double x, int n){
|
||||
long N = n;
|
||||
if (N == 0) return 1;
|
||||
double res = x;
|
||||
long num = N > 0 ? N : -N;
|
||||
for (long i = 1; i < num; i++){
|
||||
res *= x;
|
||||
}
|
||||
if (N < 0) res = 1 / res;
|
||||
return res;
|
||||
}
|
||||
```
|
||||
然而,这种解法在面对$n$比较大的情况时,效率会变得十分低下。仔细想想上面的循环过程就会发现,里面进行了很多次无意义的计算。以$a^{10}$ 举例,通过循环一个一个往上乘,需要进行$9$次运算。而如果我们先计算出$a^2$ ($1$次),然后计算$a^2*a^2*a^2*a^2*a^2$ ($4$次),总计算量就能减少到$5$次。如果先计算出$a^4$($2$次),再计算$a^2*a^4*a^4$($2$次),总计算量就能减少到$4$次。
|
||||
|
||||
也就是说,将$a^n$ 拆解成$a^x*a^y*a^z...$的形式就可以降低总体运算的次数。那么如何拆解$n$才最高效呢?根据前面的思路,显然是每次平方所需的运算次数最少。仍然是$a^{10}$ 的例子,我们从$a^1$
|
||||
开始,每次取平方值,可以得到$[a^1,a^2,a^4,a^8]$。想要组成$a^{10}$ ,只需要让$a^8*a^2$ 即可。所需的计算次数也是$4$次。看到这里有没有觉得熟悉?我们实际上就是在把$n$拆成几个$2^?$相加,也就是类似于$n$的二进制转换成十进制的过程。
|
||||
|
||||
下面仍然以$a^{10}$ 为例,通过图展示一下计算过程:
|
||||
我们从$10$的最低位开始遍历,遇到的第一位是$0$,对应的是$a^1$ ,但我们并不需要它计算结果,所以跳过。
|
||||
|
||||

|
||||
|
||||
接下来遇到的第二位是$1$,对应$a^2$ ,这是计算结果需要用到的,所以把它乘到$res$上。继续移动指针。
|
||||
|
||||

|
||||
|
||||
遇到的第三位是$0$,对应$a^4$ ,用不到,跳过。
|
||||
|
||||

|
||||
|
||||
遇到的第四位是$1$,对应$a^8$ ,需要用到,把它乘到$res$中。
|
||||
|
||||

|
||||
|
||||
|
||||
$res$便是最终结果。将上面的思路转换成代码(未考虑特殊情况):
|
||||
|
||||
```cpp {.line-numbers}
|
||||
double pow(double a, int n){
|
||||
double res = 1;
|
||||
while (n){
|
||||
// 当前位为1,计入结果
|
||||
if ((n & 1) == 1) res = res * a;
|
||||
// a自乘
|
||||
a *= a;
|
||||
// n右移
|
||||
n >>= 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
```
|
||||
|
||||
- **单位矩阵**
|
||||
|
||||
在普通的乘法中,一个数乘$1$还是等于它本身,在矩阵乘法中也有这么一个$1$,它就是 **单位矩阵**
|
||||
|
||||
不同于普通乘法中的单位$1$,对于不同矩阵他们的单位矩阵大小是不同的
|
||||
|
||||
对于$n∗m$的矩阵,它的单位矩阵大小为$m∗m$,对于$m∗n$的矩阵,它的单位矩阵大小为$n∗n$
|
||||
|
||||
也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同
|
||||
|
||||
单位矩阵的元素非$0$即$1$,从左上角到右下角的对角线上元素皆为$1$,其他皆为$0$
|
||||
|
||||
**矩阵快速幂-(单位矩阵)**
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 110;
|
||||
int n, k; // 本题数据范围很大,用int直接wa哭了
|
||||
int a[N][N], b[N][N]; // 原始矩阵,结果矩阵
|
||||
|
||||
// 矩阵乘法模板
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
cin >> n >> k;
|
||||
// 输入原始矩阵
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < n; j++)
|
||||
cin >> a[i][j];
|
||||
|
||||
// 1、单位矩阵
|
||||
for (int i = 0; i < n; i++) b[i][i] = 1;
|
||||
|
||||
// 2、矩阵快速幂
|
||||
for (int i = k; i; i >>= 1) {
|
||||
if (i & 1) mul(a, b, b);
|
||||
mul(a, a, a);
|
||||
}
|
||||
|
||||
// 3、输出
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%lld ", b[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**矩阵快速幂-(不使用单位矩阵)**
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
using namespace std;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
const int MOD = 1e9 + 7;
|
||||
const int N = 110;
|
||||
int n, k; // 本题数据范围很大,用int直接wa哭了
|
||||
int a[N][N], b[N][N]; // 原始矩阵,结果矩阵
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++)
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + a[i][k] * b[k][j] % MOD) % MOD; // 矩阵乘法
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
int main() {
|
||||
cin >> n >> k;
|
||||
// 1、输入原始矩阵
|
||||
for (int i = 0; i < n; i++)
|
||||
for (int j = 0; j < n; j++) {
|
||||
cin >> a[i][j];
|
||||
b[i][j] = a[i][j]; // 这种解法与标准解法不同,不用构建单位矩阵
|
||||
// 直接赋值初始化了一个,然后执行k-1次就完成了矩阵的k次幂
|
||||
}
|
||||
|
||||
// 2、计算矩阵快速幂
|
||||
for (int i = k - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(a, b, b);
|
||||
mul(a, a, a);
|
||||
}
|
||||
|
||||
// 3、输出
|
||||
for (int i = 0; i < n; i++) {
|
||||
for (int j = 0; j < n; j++)
|
||||
printf("%lld ", b[i][j]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
> **理解**:不管是用单位矩阵也好,不用单位矩阵也罢,本质上都是类似于构造一个乘法的基底:数字$1$!
|
||||
|
||||
**矩阵快速幂应用:斐波那契数列**
|
||||
|
||||
矩阵快速幂的一个非常典型的应用就是斐波那契数列(**[原题地址](https://leetcode.cn/problems/fei-bo-na-qi-shu-lie-lcof/)**)。先来看斐波那契数列的定义:
|
||||
$$F(1)=0,F(2)=1$$
|
||||
$$F(n)=F(n-1)+F(n-2),其中n>1$$
|
||||
|
||||
我们先定义一个矩阵
|
||||
$$b=\begin{bmatrix} F(n) & F(n-1) \end{bmatrix}$$
|
||||
|
||||
现在假设有一个变换矩阵$M$,与上述矩阵存在如下关系
|
||||
$$\begin{bmatrix}F(n) & F(n-1) \end{bmatrix} \times M= \begin{bmatrix}F(n+1) & F(n) \end{bmatrix}$$
|
||||
|
||||
很显然,$M$是一个$2×2$的矩阵,我们假设
|
||||
|
||||
$$M=\begin{bmatrix}
|
||||
a & b \\
|
||||
c & d
|
||||
\end{bmatrix}$$
|
||||
|
||||
带入上面的公式可得
|
||||
$\begin{bmatrix}F(n)& F(n-1)\end{bmatrix} \times
|
||||
\begin{bmatrix}a& b \\
|
||||
c & d \\
|
||||
\end{bmatrix}=\begin{bmatrix}
|
||||
aF(N)+cF(n-1)& bF(n)+dF(n-1)
|
||||
\end{bmatrix} =
|
||||
\begin{bmatrix} F(n+1)& F(n) \end{bmatrix}$
|
||||
|
||||
|
||||
也就是
|
||||
$$aF(n)+cF(n-1)=F(n+1)$$
|
||||
$$bF(n)+dF(n-1)=F(n)$$
|
||||
|
||||
依照$Fibonacci$的现实含义,很容易得出
|
||||
$$M=\begin{bmatrix}
|
||||
1 & 1 \\
|
||||
1 & 0
|
||||
\end{bmatrix}$$
|
||||
|
||||
即
|
||||
$$\begin{bmatrix} F(n) & F(n-1) \end{bmatrix} \times
|
||||
\begin{bmatrix} 1 & 1 \\
|
||||
1 & 0
|
||||
\end{bmatrix}=\begin{bmatrix} F(n+1) & F(n) \end{bmatrix} \ ①$$
|
||||
|
||||
|
||||
同理
|
||||
$$\begin{bmatrix} F(n-1) & F(n-2) \end{bmatrix} \times
|
||||
\begin{bmatrix} 1 & 1 \\
|
||||
1 & 0
|
||||
\end{bmatrix}=\begin{bmatrix} F(n) & F(n-1) \end{bmatrix} \ ②$$
|
||||
|
||||
将 ② 代入 ①,得
|
||||
$$\begin{bmatrix}F(n+1) & F(n) \end{bmatrix} =
|
||||
\begin{bmatrix}F(n-1) & F(n-2) \end{bmatrix} \times \begin{bmatrix}
|
||||
1 & 1 \\
|
||||
1 & 0
|
||||
\end{bmatrix} ^{2}$$
|
||||
|
||||
根据数学归纳法:
|
||||
$\begin{bmatrix} F(n-1)& F(n-2) \end{bmatrix}$ 与$M$矩阵的平方匹配.也就是$F(n-1)$中$n-1+2=n+1$,一路递推上去,就是
|
||||
|
||||
$$\begin{bmatrix}F(n+1) & F(n) \end{bmatrix} =
|
||||
\begin{bmatrix}F(2) & F(1) \end{bmatrix} \times \begin{bmatrix}
|
||||
1 & 1 \\
|
||||
1 & 0
|
||||
\end{bmatrix} ^{n-1}$$
|
||||
|
||||
我们只需要定义出矩阵乘法,配合前面的快速幂,即可实现在$O(logN)$时间复杂度内解出斐波那契数列。
|
||||
|
||||
|
||||
|
||||
|
||||
**[$YBT$_$1642$ $Fibonacci$ 第 $n$ 项](https://www.cnblogs.com/littlehb/p/17074586.html)**
|
||||
```cpp {.line-numbers}
|
||||
#include <bits/stdc++.h>
|
||||
|
||||
using namespace std;
|
||||
const int INF = 0x3f3f3f3f;
|
||||
#define int long long
|
||||
#define endl "\n"
|
||||
/*
|
||||
http://ybt.ssoier.cn:8088/problem_show.php?pid=1642
|
||||
测试用例:
|
||||
5 1000
|
||||
|
||||
答案:
|
||||
5
|
||||
*/
|
||||
const int N = 2;
|
||||
|
||||
int n, mod;
|
||||
|
||||
// 矩阵乘法
|
||||
void mul(int a[][N], int b[][N], int c[][N]) {
|
||||
int t[N][N] = {0};
|
||||
for (int i = 0; i < N; i++) {
|
||||
for (int j = 0; j < N; j++)
|
||||
for (int k = 0; k < N; k++)
|
||||
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
|
||||
}
|
||||
memcpy(c, t, sizeof t);
|
||||
}
|
||||
|
||||
signed main() {
|
||||
cin >> n >> mod;
|
||||
|
||||
int b[N][N] = {1, 1}; // 结果矩阵(初始化fib[2]=1,fib[1]=1)
|
||||
|
||||
// 构造的向量数组
|
||||
int m[N][N] = {
|
||||
{1, 1},
|
||||
{1, 0}};
|
||||
|
||||
// 矩阵快速幂
|
||||
for (int i = n - 1; i; i >>= 1) {
|
||||
if (i & 1) mul(b, m, b);
|
||||
mul(m, m, m);
|
||||
}
|
||||
|
||||
printf("%lld\n", b[0][1]);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
> **$Q_1$**:为什么在计算矩阵快速幂时提出了一个单元矩阵的概念,而在上面的斐波那契第$n$项中,却没有使用单元矩阵呢?什么时候用单元矩阵,什么时候不用呢?
|
||||
> **答**:不管是单元矩阵组装出的$1$的概念基底,还是默认把$1$次方做为基底,都是希望有一个**基底**,斐波那契数列这道题中,由于有$b[2],b[1]$组成的初始值,构成了一个 **基底** 矩阵,所以,就可以直接使用这引基底矩阵一路乘上去就行了。
|
||||
|
||||
>**$Q_2$: $b[0],b[1]$明明是一维数组,或者叫只有一行的矩阵,为什么还要声明为 $b[N][N]$呢?**
|
||||
> **答**:是因为我懒!因为我懒得要写两个矩阵乘法的模板,也懒得背两个矩阵乘法的模板!是哪两个呢?
|
||||
> - 二维乘一维
|
||||
> - 二维乘二维
|
||||
> 我整理的模板就是二维乘二维的,没有整理二维乘一维,或者,一维乘二维的。因为二维乘二维可以模拟出二维乘一维的:对于一维矩阵,只需要初始化第一行的所有数据,其它数据为$0$,就可以模拟出二维乘一维的效果了。
|
||||
|
||||
>**$Q_3$:$b$数组的含义是什么呢?**
|
||||
**答**:其实$b$矩阵是构造出来的,表现形式是$b=[F(n) \ F(n-1)]$,按题目的意思,$Fibonacci$数列是从下标$1$开始的,$f_1=f_2=1$,所以$b$的初始值就是$[F(2) \ F(1)]$
|
||||
|
||||
**[$AcWing$ $1303$. 斐波那契前 $n$ 项和](https://www.cnblogs.com/littlehb/p/16341964.html)**
|
||||
相比于上一道题,本题增加了一个概念$S_n$,含义是前$n$个$f_n$的和,难度有所增加。
|
||||
|
||||
|
||||
**[$P1939$ 矩阵加速(数列)](https://www.cnblogs.com/littlehb/p/16039658.html)**
|
||||
|
||||
|
||||
**[$AcWing$ $1304$. 佳佳的斐波那契](https://www.cnblogs.com/littlehb/p/16342848.html)**
|
||||
|
||||
|
||||
**[$AcWing$ $1305$. $GT$考试](https://www.cnblogs.com/littlehb/p/16348443.html)**
|
||||
|
||||
|
||||
https://blog.csdn.net/STRVE/article/details/106739349
|
||||
Reference in New Issue
Block a user