一、矩阵推导过程
\[\because S_n=F_1+F_2+⋯+F_n=\sum_{i=1}^{n}F_i \\
T_n=F_1+2*F_2+...+nF_n=\sum_{i=1}^{n}iF_i\]
我们需要利用\(T_n\)构造新的数列,从而消去变量\(i\),最后再反解出\(T_n\):
\[\therefore nS_n-T_n=(n-1)F_1+(n-2)F_2+...+F_{n-1}
\]
令\(C_n=nS_n-T_n\)
\[\therefore C_n=(n-1)F_1+(n-2)F_2+...+F_{n-1}
\]
\[C_{n+1}=nF_1+(n-1)F_2+...+F_{n}
\]
下式减上式
\[C_{n+1}-C_n=F_1+F_2+F_3+...+F_n=S_n
\]
于是我们只需维护如下矩阵即可
\[\begin{pmatrix}
f_{n+1} & f_n & s_n & c_n
\end{pmatrix}
\]
有如下等式:
\[\begin{pmatrix}
f_{n+1} & f_n & s_n & c_n
\end{pmatrix} \times
\begin{pmatrix}
1 & 1 & 1 & 0 \\
1 & 0 & 0 & 0 \\
0 & 0 & 1 & 1 \\
0 & 0 & 0 & 1
\end{pmatrix}=
\begin{pmatrix}
f_{n+2} & f_{n+1} & s_{n+1} & c_{n+1}
\end{pmatrix}
\]
然后直接使用矩阵快速幂便可以求解
后来的\(T_n=nS_n-C_n\)
下面两种方法都是可以完成递推的:
\[\begin{pmatrix}
f_{1} & f_{0} & s_{0} & c_{0} \\
\end{pmatrix} =
\begin{pmatrix}
1 & 0 & 0& 0
\end{pmatrix}
\]
此时要取\(n\)次幂。
\[\begin{pmatrix}
f_{2} & f_{1} & s_{1} & c_{1}
\end{pmatrix} =
\begin{pmatrix}
1 & 1 & 1 & 0
\end{pmatrix}
\]
此时要取\(n-1\)次幂。
二、实现代码I
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 4;
int n, mod;
//矩阵乘法
void mul(LL a[][N], LL b[][N], LL c[][N]) {
LL t[N][N] = {0};
for (LL i = 0; i < N; i++) {
for (LL j = 0; j < N; j++)
for (LL k = 0; k < N; k++)
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
}
memcpy(c, t, sizeof t);
}
//矩阵快速幂
// a: 初始矩阵,同时也是结果矩阵
// b: 构建的向量矩阵,需要它进行多个幂次方计算
// k: 多少次方
void qmi(LL a[][N], LL b[][N], int k) {
for (int i = k; i; i >>= 1) {
if (i & 1) mul(a, b, a); // a*b-->a
mul(b, b, b); // b*b->b
}
}
int main() {
LL a[N][N] = {1, 0, 0, 0};
LL b[N][N] = {
{1, 1, 1, 0},
{1, 0, 0, 0},
{0, 0, 1, 1},
{0, 0, 0, 1}};
cin >> n >> mod;
qmi(a, b, n);
LL t = (n * a[0][2]) - a[0][3];
t = (t % mod + mod) % mod;
printf("%lld\n", t);
return 0;
}
三、实现代码II
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 4;
int n, mod;
//矩阵乘法
void mul(LL a[][N], LL b[][N], LL c[][N]) {
LL t[N][N] = {0};
for (LL i = 0; i < N; i++) {
for (LL j = 0; j < N; j++)
for (LL k = 0; k < N; k++)
t[i][j] = (t[i][j] + (a[i][k] * b[k][j]) % mod) % mod;
}
memcpy(c, t, sizeof t);
}
//矩阵快速幂
// a: 初始矩阵,同时也是结果矩阵
// b: 构建的向量矩阵,需要它进行多个幂次方计算
// k: 多少次方
void qmi(LL a[][N], LL b[][N], int k) {
for (int i = k; i; i >>= 1) {
if (i & 1) mul(a, b, a); // a*b-->a
mul(b, b, b); // b*b->b
}
}
int main() {
LL a[N][N] = {1, 1, 1, 0}; //此处声明为二维,可以少写一个一维乘二维的函数
//这里只是第一行,其它行默认值是0,其实,其它行是啥都一样,因为计算了也不读取,没用
LL b[N][N] = {
{1, 1, 1, 0},
{1, 0, 0, 0},
{0, 0, 1, 1},
{0, 0, 0, 1}};
cin >> n >> mod;
qmi(a, b, n - 1);
LL t = (n * a[0][2]) - a[0][3];
t = (t % mod + mod) % mod;
printf("%lld\n", t);
return 0;
}