P1939 【模板】矩阵加速(数列)
题目传送门
解题思路
这道题目的关键之处在于构造初始矩阵,题目都告诉我们了要用矩阵加速。所以矩阵快速幂是核心所在。
如何构造
我们首先要确定目标矩阵。下面这个矩阵就是我想要的矩阵.
那么这个矩阵要怎样算出来。根据题目给出的递推式可以得到下面三个式子
\(f[i] = f[i-1] \times 1 + f[i-2] \times 0 + f[i-3] \times 1\)
\(f[i-1] = f[i-1] \times 1 + f[i-2] \times 0 + f[i-3] \times 0\)
\(f[i-2] = f[i-1] \times 0 + f[i-2] \times 1 + f[i-3] \times 0\)
通过每一项的系数可以得出初始矩阵为
\[\begin{bmatrix} 1 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{bmatrix} \]然后我们就可以通过矩阵快速幂进行求解。
二、实现方法I
#include
using namespace std;
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 10;
int n;
LL res[N][N], base[N][N];
inline void init() {
//结果矩阵清零
memset(res, 0, sizeof(res));
//只记录f(i),f(i-1),f(i-2)共3个,所以初始化一个3*3矩阵即可
for (int i = 1; i <= 3; i++) res[i][i] = 1;
// base数组,原理见题解
memset(base, 0, sizeof(base));
base[1][1] = base[1][3] = base[2][1] = base[3][2] = 1;
}
//矩阵乘法
inline void mul(LL C[][N], LL A[][N], LL B[][N]) {
static LL tmp[N][N];
memset(tmp, 0, sizeof(tmp));
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
for (int k = 1; k <= 3; k++) {
tmp[i][j] += (A[i][k] % MOD) * (B[k][j] % MOD);
tmp[i][j] %= MOD;
}
memcpy(C, tmp, sizeof tmp);
}
//快速幂
inline void qmi(int k) {
while (k) {
if (k & 1) mul(res, res, base);
mul(base, base, base);
k >>= 1;
}
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n;
if (n <= 3) {
printf("1\n");
continue;
}
init();
qmi(n - 1);
printf("%lld\n", res[1][1]);
}
}
三、实现方法II
#include
using namespace std;
// https://www.luogu.com.cn/blog/wlz123/solution-p1939
typedef long long LL;
const int MOD = 1e9 + 7;
const int N = 10;
int n;
//矩阵声明
struct JZ {
LL m[N][N];
} res, base;
inline void init() {
//结果矩阵清零
memset(res.m, 0, sizeof(res.m));
//只记录f(i),f(i-1),f(i-2)共3个,所以初始化一个3*3矩阵即可
for (int i = 1; i <= 3; i++) res.m[i][i] = 1;
// base数组,原理见题解
memset(base.m, 0, sizeof(base.m));
base.m[1][1] = base.m[1][3] = base.m[2][1] = base.m[3][2] = 1;
}
//矩阵乘法
inline JZ mul(JZ A, JZ B) {
JZ C;
memset(C.m, 0, sizeof(C.m));
for (int i = 1; i <= 3; i++)
for (int j = 1; j <= 3; j++)
for (int k = 1; k <= 3; k++) {
C.m[i][j] += (A.m[i][k] % MOD) * (B.m[k][j] % MOD);
C.m[i][j] %= MOD;
}
return C;
}
//快速幂
inline void qmi(int k) {
while (k) {
if (k & 1) res = mul(res, base);
base = mul(base, base);
k >>= 1;
}
}
int main() {
int T;
cin >> T;
while (T--) {
cin >> n;
if (n <= 3) {
printf("1\n");
continue;
}
init();
qmi(n - 1);
printf("%lld\n", res.m[1][1]);
}
}