链接:https://ac.nowcoder.com/acm/contest/105/G
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
这是一个加强版的斐波那契数列。
给定递推式
求F(n)的值,由于这个值可能太大,请对10^9+7取模。
输入描述:
第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数n(1 ≤ n ≤ 10^18)。
输出描述:
每个样例输出一行,一个整数,表示F(n) mod 1000000007。
示例1
输入
4
1
2
3
100
输出
1
16
57
558616258
解题思路:
这个公式相比普通的斐波那契数列多了后面四项,看一眼数据范围,肯定不能使用普通的 o(n) 算法了,因此这里需要使用矩阵快速幂(斐波那契数列的项数n一旦过大,就要考虑快速幂,普通算法时间、空间开销都太大)
对于给定的递推式:
我们可以得到如下矩阵形式:
[
F
i
F
i
−
1
(
i
+
1
)
3
(
i
+
1
)
2
i
+
1
1
]
=
[
1
1
1
1
1
1
1
0
0
0
0
0
0
0
1
3
3
1
0
0
0
1
2
1
0
0
0
0
1
1
0
0
0
0
0
1
]
[
F
i
−
1
F
i
−
2
i
3
i
2
i
1
]
\left[ \begin{matrix} F_i\\ F_{i-1} \\ (i+1)^3\\ (i+1)^2 \\ i+1\\ 1 \end{matrix} \right]= \left[ \begin{matrix} 1 & 1& 1 & 1 & 1& 1\\ 1 & 0& 0 & 0 & 0& 0\\ 0 & 0& 1 & 3& 3& 1\\ 0 & 0& 0 & 1& 2& 1\\ 0 & 0& 0 & 0& 1& 1\\ 0 & 0& 0 & 0& 0& 1 \end{matrix} \right] \left[ \begin{matrix} F_{i-1}\\ F_{i-2} \\ i^3\\ i^2 \\ i\\ 1 \end{matrix} \right]
⎣⎢⎢⎢⎢⎢⎢⎡FiFi−1(i+1)3(i+1)2i+11⎦⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎡110000100000101000103100103210101111⎦⎥⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎡Fi−1Fi−2i3i2i1⎦⎥⎥⎥⎥⎥⎥⎤
又有F(0)=0,F(1)=1,可得
[
F
i
F
i
−
1
(
i
+
1
)
3
(
i
+
1
)
2
i
+
1
1
]
=
[
1
1
1
1
1
1
1
0
0
0
0
0
0
0
1
3
3
1
0
0
0
1
2
1
0
0
0
0
1
1
0
0
0
0
0
1
]
i
−
1
[
F
1
F
0
2
3
2
2
2
1
]
=
[
1
1
1
1
1
1
1
0
0
0
0
0
0
0
1
3
3
1
0
0
0
1
2
1
0
0
0
0
1
1
0
0
0
0
0
1
]
i
−
1
[
1
0
8
4
2
1
]
\left[ \begin{matrix} F_i\\ F_{i-1} \\ (i+1)^3\\ (i+1)^2 \\ i+1\\ 1 \end{matrix} \right] = \left[ \begin{matrix} 1 & 1& 1 & 1 & 1& 1\\ 1 & 0& 0 & 0 & 0& 0\\ 0 & 0& 1 & 3& 3& 1\\ 0 & 0& 0 & 1& 2& 1\\ 0 & 0& 0 & 0& 1& 1\\ 0 & 0& 0 & 0& 0& 1 \end{matrix} \right]^{i-1} \left[ \begin{matrix} F_{1}\\ F_{0} \\ 2^3\\ 2^2 \\ 2\\ 1 \end{matrix} \right] = \left[ \begin{matrix} 1 & 1& 1 & 1 & 1& 1\\ 1 & 0& 0 & 0 & 0& 0\\ 0 & 0& 1 & 3& 3& 1\\ 0 & 0& 0 & 1& 2& 1\\ 0 & 0& 0 & 0& 1& 1\\ 0 & 0& 0 & 0& 0& 1 \end{matrix} \right]^{i-1} \left[ \begin{matrix} 1\\ 0\\ 8\\ 4 \\ 2\\ 1 \end{matrix} \right]
⎣⎢⎢⎢⎢⎢⎢⎡FiFi−1(i+1)3(i+1)2i+11⎦⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎡110000100000101000103100103210101111⎦⎥⎥⎥⎥⎥⎥⎤i−1⎣⎢⎢⎢⎢⎢⎢⎡F1F0232221⎦⎥⎥⎥⎥⎥⎥⎤=⎣⎢⎢⎢⎢⎢⎢⎡110000100000101000103100103210101111⎦⎥⎥⎥⎥⎥⎥⎤i−1⎣⎢⎢⎢⎢⎢⎢⎡108421⎦⎥⎥⎥⎥⎥⎥⎤
AC代码:
#include<iostream>
#include<stdio.h>
#include<vector>
using namespace std;
typedef long long ll;
// 用二维vector来表示矩阵
//注意使用ll类型
typedef vector<ll> vec;
typedef vector<vec> mat;
const int M = 1e9 + 7;
mat mul(mat a, mat b) {
mat c(a.size(), vec(b[0].size()));
for (int i = 0; i < a.size(); i++) {
for (int k = 0; k < b.size(); k++) {
for (int j = 0; j < b[0].size(); j++) {
c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % M;
}
}
}
return c;
}
mat mod_pow(mat a, ll n) {
mat b(a.size(), vec(a.size()));
for (int i = 0; i < a.size(); i++) {
b[i][i] = 1;
}
while (n > 0) {
if (n & 1) b = mul(b, a);
a = mul(a, a);
n >>= 1;
}
return b;
}
int main() {
int t; ll n;
scanf("%d", &t);
while (t--) {
scanf("%lld", &n);
if (n == 1) {
printf("%d\n", 1);
continue;
}
mat a(6, vec(6));//当然这一步已经包含了初始化为0 下面赋值的时候只将不为0的项重新赋值也可以
a[0][0] = 1; a[0][1] = 1; a[0][2] = 1; a[0][3] = 1; a[0][4] = 1; a[0][5] = 1;
a[1][0] = 1; a[1][1] = 0; a[1][2] = 0; a[1][3] = 0; a[1][4] = 0; a[1][5] = 0;
a[2][0] = 0; a[2][1] = 0; a[2][2] = 1; a[2][3] = 3; a[2][4] = 3; a[2][5] = 1;
a[3][0] = 0; a[3][1] = 0; a[3][2] = 0; a[3][3] = 1; a[3][4] = 2; a[3][5] = 1;
a[4][0] = 0; a[4][1] = 0; a[4][2] = 0; a[4][3] = 0; a[4][4] = 1; a[4][5] = 1;
a[5][0] = 0; a[5][1] = 0; a[5][2] = 0; a[5][3] = 0; a[5][4] = 0; a[5][5] = 1;
a = mod_pow(a, n - 1);
ll ans;
ans = (a[0][0] + 8*a[0][2] + 4*a[0][3] + 2*a[0][4] + a[0][5]) % M;
printf("%lld\n", ans);
}
}