1. 程式人生 > 遊戲 >《艾爾登法環》NPC捏臉資料視訊 快來捏個老婆玩

《艾爾登法環》NPC捏臉資料視訊 快來捏個老婆玩

題目傳送門

解題思路
這道題目的關鍵之處在於構造初始矩陣,題目都告訴我們了要用矩陣加速。所以矩陣快速冪是核心所在。

如何構造
我們首先要確定目標矩陣。下面這個矩陣就是我想要的矩陣.

\[\begin{bmatrix} F[i] \\ F[i-1] \\ F[i-2] \end{bmatrix} \]

那麼這個矩陣要怎樣算出來。根據題目給出的遞推式可以得到下面三個式子
\(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]);
    }
}