又见斐波拉契(矩阵快速幂)

本文介绍了一种利用矩阵快速幂解决大规模斐波那契数列计算的方法,适用于求解递推式中非常大的项数。通过构建特定矩阵并运用快速幂技巧,文章提供了一个高效的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

描述

传送门:2018年湘潭大学程序设计竞赛-G


这是一个加强版的斐波那契数列。

给定递推式
求F(n)的值,由于这个值可能太大,请对$10^9+7$取模。

Input

第一行是一个整数T(1 ≤ T ≤ 1000),表示样例的个数。
以后每个样例一行,是一个整数$n(1 ≤ n ≤ 10^18)$。

Output

每个样例输出一行,一个整数,表示F(n) mod 1000000007。

Examples

  • intput

    1
    2
    3
    4
    5
    4
    1
    2
    3
    100
  • output

    1
    2
    3
    4
    1
    16
    57
    558616258

思路

  • n最大$10^18$,O(n)肯定会T,可以考虑矩阵快速幂求解。
  • 由于题目给了递推式,所以很显然我们需要求一个$X$矩阵,使得这个矩阵满足
    ,易得。
    将$F_{i},F_{i - 1},(i + 1)^3,(i + 1)^2$按递推式展开,取对应系数即可,
  • 递推式是从2开始的,所以对与第$n$项,只需求$X^{n-1}$,所得矩阵再左乘一个$\begin{bmatrix}F_1 & F_0 & 2^3 & 2^2 & 2 & 1\end{bmatrix}^{-1}$,所得矩阵的第一个元素即为$F_i$

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define repd(i,a,n) for(int i=n-1;i>=a;i--)
#define CRL(a,x) memset(a,x,sizeof(a))
typedef long long ll;
const ll mod= 1e9+7;

struct Mat{ //矩阵
ll data[6][6];
Mat(){CRL(data,0);}
Mat operator* (Mat &a) const{ //重载*运算符
Mat c;
rep(i,0,6)
rep(j,0,6)
rep(k,0,6)
c.data[i][j]=(c.data[i][j]+data[i][k]*a.data[k][j]%mod)%mod;
return c;
}
};

Mat Mat_qpow(Mat a,ll n){ //矩阵快速幂
Mat tem;rep(i,0,6) tem.data[i][i]=1; //单位阵初始化
while(n){
if(n&1) tem=tem*a;
a=a*a;
n>>=1;
}
return tem;
}

ll M[6][6] = { //常数阵,即上面提到的X矩阵
{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}
};

int main()
{
Mat a,ans;
memcpy(a.data,M,sizeof(M));
int t;ll n;
scanf("%d",&t);
while(t--){
scanf("%lld",&n);
if(n<2LL) {printf("%lld\n",n);continue;}//特判
ans=Mat_qpow(a,n-1);
printf("%lld\n",(ans.data[0][0]+ans.data[0][2]*8%mod+ans.data[0][3]*4%mod+ans.data[0][4]*2%mod+ans.data[0][5])%mod);
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值