CF1182E 题解

前言

题目传送门!

更好的阅读体验?

zlt 推荐矩阵加速题目。其实很不算难啊,不就是模拟吗。

思路

首先乘法是不能用矩阵加速直接维护的,考虑答案为 \(f_n = c^{k_1} \times f_1^{k_2} \times f_2^{k_3} \times f_3^{k_4}\)

这些都是可以转移的。

对于 \(c\)指数的转移:\(\begin{pmatrix}t_{i-2}, t_{i-1}, t_i, 2i-6, 1\end{pmatrix}\) 分别表示最近的三项(\(f_{i-2}, f_{i-1}, f_i\))的 \(c\) 的指数、以及一些常数。

\[f_{i+1} = c^{2i - 6} \times f_i \times f_{i-1} \times f_{i-2} \]

\(\therefore\) 对应的指数 \(k_{i+1} = 2\cdot(i + 1) - 6 + k_i + k_{i-1} + k_{i-2}\)

矩阵转移:

\[\begin{pmatrix} t_{i-2} & t_{i-1} & t_i & 2i-6 & 1 \end{pmatrix} \times \begin{pmatrix} 0 & 0 & 1 & 0 & 0 \\ 1 & 0 & 1 & 0 & 0 \\ 0 & 1 & 1 & 0 & 0 \\ 0 & 0 & 1 & 1 & 0 \\ 0 & 0 & 2 & 2 & 1 \\ \end{pmatrix} = \begin{pmatrix} t_{i-1} & t_i & t_{i+1} & 2\cdot(i+1)-6 & 1 \end{pmatrix} \]


对于 \(f_1\)指数的转移:\(\{t_{i-2}, t_{i-1}, t_i\}\) 分别表示最近的三项(\(f_{i-2}, f_{i-1}, f_i\))的 \(f_1\) 的指数。

\[f_{i+1} = c^{2i - 6} \times f_i \times f_{i-1} \times f_{i-2} \]

\(\therefore\) 对应的指数 \(k_{i+1} = k_i + k_{i-1} + k_{i-2}\)

矩阵转移:

\[\begin{pmatrix} t_{i-2} & t_{i-1} & t_i \end{pmatrix} = \begin{pmatrix} 0 & 0 & 1 \\ 1 & 0 & 1 \\ 0 & 1 & 1 \end{pmatrix} \times \begin{pmatrix} t_{i-1} & t_i & t_{i+1} \end{pmatrix} \]


对于 \(f_2\)\(f_3\) 的指数转移,矩阵转移是与 \(f_1\) 的相同的。

仅仅是初始化不同。


三者对应的指数就是第 \(3\) 项,这个自己对上即可。

最后再上快速幂即可求出。

代码

不喜欢用重载(次次考场都不会写重载格式),所以代码看起来会很长。

代码其实不用放的,抄一遍上面的矩阵即可。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int mod = 1e9 + 7;
typedef long long ll;

namespace martix_3 { //矩阵快速幂,懂的直接忽略即可
    void mul(int ANS[][3], int x[][3], int y[][3])
    {
        int ans[3][3] = {};
        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                for (int k = 0; k < 3; k++)
                    ans[i][j] = (ans[i][j] + 1ll * x[i][k] * y[k][j]) % (mod - 1);
        memcpy(ANS, ans, sizeof ans);
    }
    void ksm(int f[][3], int a[][3], ll y)
    {
        while (y)
        {
            if (y & 1) mul(f, f, a);
            mul(a, a, a);
            y >>= 1;
        }
    }
};
namespace martix_5 { //矩阵快速幂,懂的直接忽略即可
    void mul(int ANS[][5], int x[][5], int y[][5])
    {
        int ans[5][5] = {};
        for (int i = 0; i < 5; i++)
            for (int j = 0; j < 5; j++)
                for (int k = 0; k < 5; k++)
                    ans[i][j] = (ans[i][j] + 1ll * x[i][k] * y[k][j]) % (mod - 1);
        memcpy(ANS, ans, sizeof ans);
    }
    void ksm(int f[][5], int a[][5], ll y)
    {
        while (y)
        {
            if (y & 1) mul(f, f, a);
            mul(a, a, a);
            y >>= 1;
        }
    }
};
int qpow(int x, int y) //快速幂,懂的直接忽略即可
{
    int ans = 1;
    while (y)
    {
        if (y & 1) ans = (1ll * ans * x) % mod;
        x = (1ll * x * x) % mod;
        y >>= 1;
    }
    return ans;
}
int main()
{
    ll n; int f1, f2, f3, c;
    cin >> n >> f1 >> f2 >> f3 >> c;

    int getc_f[5][5] = {0, 0, 0, 0, 1}; //i=3,算c
    int getc_a[5][5] = {
        0, 0, 1, 0, 0,
        1, 0, 1, 0, 0, 
        0, 1, 1, 0, 0,
        0, 0, 1, 1, 0,
        0, 0, 2, 2, 1
    };
    martix_5::ksm(getc_f, getc_a, n - 3);
    int c_k = getc_f[0][2];

    int getf1_f[3][3] = {1, 0, 0}; //i=3,算f1
    int getf1_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf1_f, getf1_a, n - 3);
    int f1_k = getf1_f[0][2];

    int getf2_f[3][3] = {0, 1, 0}; //i=3,算f2
    int getf2_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf2_f, getf2_a, n - 3);
    int f2_k = getf2_f[0][2];

    int getf3_f[3][3] = {0, 0, 1}; //i=3,算f3
    int getf3_a[3][3] = {
        0, 0, 1, 
        1, 0, 1, 
        0, 1, 1
    };
    martix_3::ksm(getf3_f, getf3_a, n - 3);
    int f3_k = getf3_f[0][2];

    //printf("f_n = c^%d * f1^%d * f2^%d * f3^%d\n", c_k, f1_k, f2_k, f3_k);
    int ans = 1;
    ans = 1ll * ans * qpow(c, c_k) % mod;
    ans = 1ll * ans * qpow(f1, f1_k) % mod;
    ans = 1ll * ans * qpow(f2, f2_k) % mod;
    ans = 1ll * ans * qpow(f3, f3_k) % mod;
    cout << ans;
    return 0;
}

希望能帮助到大家!

posted @ 2022-12-11 18:14  liangbowen  阅读(47)  评论(0编辑  收藏  举报