《艾爾登法環》NPC捏臉資料視訊 快來捏個老婆玩
阿新 • • 發佈:2022-03-18
解題思路
這道題目的關鍵之處在於構造初始矩陣,題目都告訴我們了要用矩陣加速。所以矩陣快速冪是核心所在。
如何構造
我們首先要確定目標矩陣。下面這個矩陣就是我想要的矩陣.
那麼這個矩陣要怎樣算出來。根據題目給出的遞推式可以得到下面三個式子
\(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 <bits/stdc++.h> 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 <bits/stdc++.h> 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]); } }