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;
}
希望能帮助到大家!