51Nod 1242 斐波那契数列的第N项——————矩阵快速幂

阅读 66

2022-10-18


1242 斐波那契数列的第N项

基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注

斐波那契数列的定义如下:


给出,求,由于结果很大,输出的结果即可。

Input
输入1个数n(1 <= n <= 10^18)。
Output
输出的结果。

Input示例
11
Output示例
89

矩阵快速幂模板

矩阵

数学上,一个m×n的矩阵是一个由m行n列元素排列成的矩形阵列。矩阵里的元素可以是数字、符号或数学式。

大小相同(行数列数都相同)的矩阵之间可以相互加减,具体是对每个位置上的元素做加减法。矩阵的乘法则较为复杂。两个矩阵可以相乘,当且仅当第一个矩阵的列数等于第二个矩阵的行数。矩阵的乘法满足结合律和分配律,但不满足交换律。

矩阵乘法

矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有定义。一般单指矩阵乘积时,指的便是一般矩阵乘积。若A为 矩阵,B为 矩阵,则他们的乘积(有时记做)会是一个 矩阵。其乘积矩阵的元素如下面式子得出:

线性递推关系与矩阵乘法

设数列 满足 阶常系数线性递推关系:

为常数,则构造转移矩阵

与初始向量

易见

事实上我们可以发现,对于任意的 阶常系数线性递推关系,我们总可以构造一个 的转移矩阵 , 对于初始值向量

使得 第一行第一列的元素恰好为

代码

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int INF = 0x3f3f3f3f;
const int MAX_N = 10;
const int MOD = 1000000009;
ll N;//矩阵的大小
ll b_n=0;//常数
ll C[MAX_N];//系数
ll h[MAX_N];//
struct mat{ll m[MAX_N][MAX_N]; };

mat mul(mat a,mat b)//矩阵乘法
{
mat tmp;
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
{
tmp.m[i][j]=0;
for(int k=1;k<=N;k++)
tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j])%MOD;
}
return tmp;
}
mat pow_mod(mat a,ll n)
{
mat res;
//构造单位矩阵,res相当于快速幂里的 1
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
res.m[i][j] = (i==j);

//矩阵快速幂
while(n)
{
if(n&1) res = mul(res,a);
a = mul(a,a);
n>>=1;
}
return res;
}
void init(mat &res,mat &H)//矩阵的初始化
{
for(int i=1;i<=N;i++)
res.m[1][i] = C[i];
res.m[1][N]=b_n;
//构造矩阵
for(int i=2;i<=N;i++)
for(int j=1;j<=N;j++)
res.m[i][j] = (i==j+1);

res.m[N][N-1] = 0;
res.m[N][N] = 1;

for(int i=1;i<=N;i++)
{
H.m[i][1] = h[N-i];
for(int j=2;j<=N;j++)
H.m[i][j] = 0;
}
H.m[N][1]=1;
}

void slove(ll k,ll n)
{
mat res,H;
init(res,H);

res = pow_mod(res,n-k+1);
res = mul(res,H);
ll ans=res.m[1][1];

printf("%lld\n",ans);
}
int main()
{
ll n,k=2;
C[1]=1;
C[2]=1;
N=k+1;
h[1]=0;
h[2]=1;
while(~scanf("%lld",&n))
slove(k,n);
return 0;
}


精彩评论(0)

0 0 举报