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

1242 斐波那契数列的第N项

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

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

F ( 0 ) = 0 F ( 1 ) = 1 F ( n ) = F ( n 1 ) + F ( n 2 ) ( n > = 2 ) F(0) = 0 \\ F(1) = 1\\ F(n) = F(n - 1) + F(n - 2)\qquad (n >= 2)

( 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 , 89 , 144 , 233 , 377 , . . . ) (1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, ...)
给出 n n ,求 F ( n ) F(n) ,由于结果很大,输出    F ( n ) % 1000000009      \;F(n) \% 1000000009\;\; 的结果即可。

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

Input示例
11
Output示例
89


矩阵快速幂模板

矩阵

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

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

矩阵乘法

矩阵相乘最重要的方法是一般矩阵乘积。它只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有定义。一般单指矩阵乘积时,指的便是一般矩阵乘积。若A为 m × n {\displaystyle m\times n} 矩阵,B为 n × p {\displaystyle n\times p} 矩阵,则他们的乘积 A B &ThickSpace; AB\; (有时记做 A B A · B )会是一个 m × p {\displaystyle m\times p} 矩阵。其乘积矩阵的元素如下面式子得出:
( A B ) i j = r = 1 n a i r b r j = a i 1 b 1 j + a i 2 b 2 j + + a i n b n j . \Large (AB)_{ij}=∑_{r=1}^n a_{ir}b_{rj}=a_{i1}b_{1j}+a_{i2}b_{2j}+⋯+a_{in}b_{nj}.

线性递推关系与矩阵乘法

设数列 h n {h_n} 满足 k k 阶常系数线性递推关系:
h n = C 1 h n 1 + C 2 h n 2 + C 3 h n 3 + + C k h n k + b n h_n = C_1h_{n−1} + C_2h_{n−2} + C_3h_{n−3} +···+ C_kh_{n−k}+b_n
b n b_n 可以为常数,也可以是关于n的函数

b n b_n 为常数,则构造转移矩阵
M = ( C 1 C 2 C 3 C k 1 C k b n 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 ) ( k + 1 ) × ( k + 1 ) \large M=\begin {pmatrix} C_1 &amp; C_2 &amp; C_3 &amp; \cdots &amp; C_{k-1} &amp; C_k &amp; b_n \\ 1 &amp; 0 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ 0 &amp; 1 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ 0 &amp; 0 &amp; 1 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ \vdots &amp; \vdots&amp; \vdots &amp; \ddots &amp; \vdots &amp; \vdots \\ 0 &amp; 0 &amp; 0 &amp; \cdots &amp; 1 &amp; 0 &amp; 0\\ 0 &amp; 0 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 1 \end{pmatrix}_{(k+1)×(k+1)}
与初始向量
X = ( h k 1 h k 2 h k 3 h 2 h 1 h 0 1 ) ( k + 1 ) × 1 \large X=\begin{pmatrix} h_{k-1} \\ h_{k-2} \\ h_{k-3} \\ \vdots \\ h_{2} \\ h_{1} \\ h_{0} \\ 1 \\ \end{pmatrix}_{(k+1)×1}
易见
X = ( C 1 C 2 C 3 C k 1 C k b n 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 ) ( h k 1 h k 2 h k 3 h 2 h 1 h 0 1 ) = ( h k h k 1 h k 2 h 3 h 2 h 1 1 ) \large X=\begin {pmatrix} C_1 &amp; C_2 &amp; C_3 &amp; \cdots &amp; C_{k-1} &amp; C_k &amp; b_n \\ 1 &amp; 0 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ 0 &amp; 1 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ 0 &amp; 0 &amp; 1 &amp; \cdots &amp; 0 &amp; 0 &amp; 0\\ \vdots &amp; \vdots&amp; \vdots &amp; \ddots &amp; \vdots &amp; \vdots \\ 0 &amp; 0 &amp; 0 &amp; \cdots &amp; 1 &amp; 0 &amp; 0\\ 0 &amp; 0 &amp; 0 &amp; \cdots &amp; 0 &amp; 0 &amp; 1 \end{pmatrix} \begin{pmatrix} h_{k-1} \\ h_{k-2} \\ h_{k-3} \\ \vdots \\ h_{2} \\ h_{1} \\ h_{0} \\ 1 \\ \end{pmatrix} =\begin{pmatrix} h_{k} \\ h_{k-1} \\ h_{k-2} \\ \vdots \\ h_{3} \\ h_{2} \\ h_{1} \\ 1 \\ \end{pmatrix}
事实上我们可以发现,对于任意的 k k 阶常系数线性递推关系,我们总可以构造一个 k × k k×k ( k + 1 ) × ( k + 1 ) (k+1)×(k+1) 的转移矩阵 M M , 对于初始值向量
X = ( h k 1 h k 2 h k 3 h 2 h 1 h 0 ) k × 1 ( h k 1 h k 2 h k 3 h 1 h 0 b n ) ( k + 1 ) × 1 \large X=\begin{pmatrix} h_{k-1} \\ h_{k-2} \\ h_{k-3} \\ \vdots \\ h_{2} \\ h_{1} \\ h_{0} \\ \end{pmatrix}_{k×1}或 \begin{pmatrix} h_{k-1} \\ h_{k-2} \\ h_{k-3} \\ \vdots \\ h_{1} \\ h_{0} \\ b_n \\ \end{pmatrix}_{(k+1)×1}
使得 Y = M n k + 1 X Y = M^{n−k+1}X 第一行第一列的元素恰好为 h n h_n


代码

#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;
}

猜你喜欢

转载自blog.csdn.net/Hpuer_Random/article/details/82950390