关于快速幂的讲解可以参见我的上一篇博客《快速幂》
题目链接:又见斐波那契
题目描述
这是一个加强版的斐波那契数列。
给定递推式

求F(n)的值,由于这个值可能太大,请对10
9+7取模。
输入描述:
第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数n(1 ≤ n ≤ 1018)。
输出描述:
每个样例输出一行,一个整数,表示F(n) mod 1000000007。
这个相比普通的斐波那契数列多了后面四项,看一眼数据范围,使用普通的o(n)的算法肯定会超时,
因此这里需要使用矩阵快速幂(斐波那契数列的项数n一旦过大,就要考虑快速幂,普通算法时间空间都开销太大)。
使用矩阵快速幂的一个关键问题就是矩阵递推式。
参考普通快速幂那一片博客最后面的那个扩展式,就可以得到下面这个递推式了:
然后通过计算等价替换可得出该矩阵A:
下面只需要把普通斐波那契数列的构造由2*2的矩阵换为6*6的即可。
-
-
-
-
-
-
-
using namespace std;
-
-
typedef long long ll;
-
-
// 用二维vector来表示矩阵
-
typedef vector<ll> vec;
-
typedef vector<vec> mat;
-
-
// 模
-
const int M = 1000000007;
-
-
// 计算 A*B
-
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)%M;
-
}
-
}
-
}
-
return C;
-
}
-
-
// 计算 A^B
-
mat 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;
-
scanf( "%d", &T );
-
ll n;
-
mat A(6, vec(6));
-
while ( T -- ) {
-
scanf( "%lld", &n );
-
if ( n == 0 ) { puts( "0" ); continue; }
-
if ( n == 1 ) { puts( "1" ); continue; }
-
for ( int i = 0 ; i < 6 ; ++ i ) {
-
for ( int j = 0 ; j < 6 ; ++ j ) {
-
A[i][j] = 0;
-
}
-
}
-
A[ 0][ 0] = 1; A[ 0][ 1] = 1; A[ 0][ 2] = 1; A[ 0][ 3] = 4; A[ 0][ 4] = 6; A[ 0][ 5] = 4;
-
A[ 1][ 0] = 1;
-
A[ 2][ 2] = 1; A[ 2][ 3] = 3; A[ 2][ 4] = 3; A[ 2][ 5] = 1;
-
A[ 3][ 3] = 1; A[ 3][ 4] = 2; A[ 3][ 5] = 1;
-
A[ 4][ 4] = 1; A[ 4][ 5] = 1;
-
A[ 5][ 5] = 1;
-
A = pow(A, n -1);
-
ll ans = 0;
-
for ( int i = 0 ; i < 6 ; ++ i ) {
-
if ( i == 1 ) continue;
-
ans = (ans+A[ 0][i])%M;
-
}
-
printf( "%lld\n", ans );
-
}
-
return 0;
-
}