Fibonacci(矩阵快速幂 - 递推式构造 + 变种)

POJ 3070 Fibonacci

题目链接:http://poj.org/problem?id=3070
在这里插入图片描述

题意:求Fn % 1000是多少?(公式题目已给出)
此题的公式就是Fn = Fn-1 + Fn-2,我们令:
   X n − 1 = [ F n − 1 F n − 2 ] X_{n-1} = \begin{bmatrix}F_{n-1}\\ F_{n-2} \end{bmatrix} Xn1=[Fn1Fn2]   X n = [ F n F n − 1 ] X_{n} = \begin{bmatrix} F_{n}\\ F_{n-1} \end{bmatrix} Xn=[FnFn1]
那么我们需要找到的矩阵 A 就满足:
       A ⋅ X n − 1 = X n A \cdot X_{n-1} = X_{n} AXn1=Xn
又因为:
     { F n = F n − 1 + F n − 2 F n − 1 = F n − 1 + 0 ⋅ F n − 2 \begin{cases} F_{n} = F_{n-1} + F_{n-2}\\ F_{n-1} = F_{n-1} + 0 \cdot F_{n-2} \end{cases} {Fn=Fn1+Fn2Fn1=Fn1+0Fn2
所以:
     A = [ 1 , 1 0 , 0 ] A = \begin{bmatrix} 1,1\\ 0,0 \end{bmatrix} A=[1,10,0]
即:
     [ 1 , 1 0 , 0 ] \begin{bmatrix} 1,1\\ 0,0 \end{bmatrix} [1,10,0] ⋅ \cdot [ F n − 1 F n − 2 ] \begin{bmatrix}F_{n-1}\\ F_{n-2} \end{bmatrix} [Fn1Fn2] = [ F n F n − 1 ] = \begin{bmatrix} F_{n}\\ F_{n-1} \end{bmatrix} =[FnFn1]
综上所述:
     [ F n F n − 1 ] = [ 1 , 1 0 , 0 ] ⋅ [ F n − 1 F n − 2 ] = [ 1 , 1 0 , 0 ] 2 ⋅ [ F n − 2 F n − 3 ] ⋅ ⋅ ⋅ ⋅ = [ 1 , 1 0 , 0 ] n − 1 ⋅ [ F 1 F 0 ] \begin{bmatrix} F_{n}\\ F_{n-1} \end{bmatrix} = \begin{bmatrix} 1,1\\ 0,0 \end{bmatrix} \cdot \begin{bmatrix}F_{n-1}\\ F_{n-2} \end{bmatrix} = \begin{bmatrix} 1,1\\ 0,0 \end{bmatrix}^{2} \cdot \begin{bmatrix}F_{n-2}\\ F_{n-3} \end{bmatrix} \cdot \cdot \cdot \cdot =\begin{bmatrix} 1,1\\ 0,0 \end{bmatrix}^{n-1} \cdot \begin{bmatrix}F_{1}\\ F_{0} \end{bmatrix} [FnFn1]=[1,10,0][Fn1Fn2]=[1,10,0]2[Fn2Fn3]=[1,10,0]n1[F1F0]


我们用矩阵快速幂求出 [ 1 , 1 0 , 0 ] n − 1 \begin{bmatrix} 1,1\\ 0,0 \end{bmatrix}^{n-1} [1,10,0]n1后,结果矩阵的第一行与上面公式中最后的 [ F 1 F 0 ] \begin{bmatrix}F_{1}\\ F_{0} \end{bmatrix} [F1F0]做矩阵乘法即是最终结果。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 10000
using namespace std;

typedef long long LL;
const int Max_n=100005;

struct Mat{
    int mat[2][2];
};

Mat mul(Mat a,Mat b){
    Mat ans;
    for(int i=0;i<2;i++){
        for(int j=0;j<2;j++){
            ans.mat[i][j]=0;
            for(int k=0;k<2;k++)
                ans.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;
                ans.mat[i][j]%=mod;
        }
    }
    return ans;
}

Mat q_pow(Mat a,int b){
    Mat ans={1,0,0,1};
    Mat res=a;
    while(b){
        if(b&1) ans=mul(ans,res);
        res=mul(res,res);
        b>>=1;
    }
    return ans;
}
int main(){
    int n;
    while(~scanf("%d",&n)&&n!=-1){
        Mat a={1,1,1,0};
        Mat ans={0,0,0,0};
        ans=q_pow(a,n); 
        printf("%d\n",ans.mat[0][1]);
    }
    return 0;
}

2018年湘潭大学程序设计竞赛 G 又见斐波那契

题目地址:https://ac.nowcoder.com/acm/contest/105/G?&headNav=www&headNav=acm
本题需要注意的点就是矩阵的数据类型,用int中间运算会爆掉,所以构造矩阵的时候需要用 ll
思路:与上面题目套路相同
   X n − 1 = [ F n − 1 F n − 2 i 3 i 2 i 1 ] X_{n-1} = \begin{bmatrix} F_{n-1}\\ F_{n-2} \\ i^{3}\\ i^{2}\\ i\\ 1 \end{bmatrix} Xn1=Fn1Fn2i3i2i1   X n = [ F n F n − 1 ( i + 1 ) 3 ( i + 1 ) 2 ( i + 1 ) 1 ] X_{n} = \begin{bmatrix} F_{n}\\ F_{n-1} \\ (i+1)^{3}\\ (i+1)^{2}\\ (i+1)\\ 1 \end{bmatrix} Xn=FnFn1(i+1)3(i+1)2(i+1)1   A ⋅ X n − 1 = X n A \cdot X_{n-1} = X_{n} AXn1=Xn


   [ X , X , X , X , X , X X , X , X , X , X , X X , X , X , X , X , X X , X , X , X , X , X X , X , X , X , X , X X , X , X , X , X , X ] \begin{bmatrix} X,X,X,X,X,X\\ X,X,X,X,X,X\\ X,X,X,X,X,X\\ X,X,X,X,X,X\\ X,X,X,X,X,X\\ X,X,X,X,X,X \end{bmatrix} X,X,X,X,X,XX,X,X,X,X,XX,X,X,X,X,XX,X,X,X,X,XX,X,X,X,X,XX,X,X,X,X,X ⋅ \cdot [ F n − 1 F n − 2 ( i + 1 ) 3 ( i + 1 ) 2 i + 1 1 ] \begin{bmatrix}F_{n-1}\\ F_{n-2} \\ (i+1)^{3}\\ (i+1)^{2}\\ i+1\\ 1 \end{bmatrix} Fn1Fn2(i+1)3(i+1)2i+11 = [ F n F n − 1 i 3 i 2 i 1 ] = \begin{bmatrix} F_{n}\\ F_{n-1} \\ i^{3}\\ i^{2}\\ i\\ 1 \end{bmatrix} =FnFn1i3i2i1


{ F n = 1 ⋅ F n − 1 + 1 ⋅ F n − 2 + 1 ⋅ i 3 + 1 ⋅ i 2 + 1 ⋅ i + 1 ⋅ 1 F n − 1 = 1 ⋅ F n − 1 + 0 ⋅ F n − 2 + 0 ⋅ i 3 + 0 ⋅ i 2 + 0 ⋅ i + 0 ⋅ 1 ( i + 1 ) 3 = 0 ⋅ F n − 1 + 0 ⋅ F n − 2 + 1 ⋅ i 3 + 3 ⋅ i 2 + 3 ⋅ i + 1 ⋅ 1 ( i + 1 ) 2 = 0 ⋅ F n − 1 + 0 ⋅ F n − 2 + 0 ⋅ i 3 + 1 ⋅ i 2 + 2 ⋅ i + 1 ⋅ 1 i + 1 = 0 ⋅ F n − 1 + 0 ⋅ F n − 2 + 0 ⋅ i 3 + 0 ⋅ i 2 + 1 ⋅ i + 1 ⋅ 1 1 = 0 ⋅ F n − 1 + 0 ⋅ F n − 2 + 0 ⋅ i 3 + 0 ⋅ i 2 + 0 ⋅ i + 1 ⋅ 1 \begin{cases} F_{n} = 1 \cdot F_{n-1} + 1 \cdot F_{n-2} + 1 \cdot i^{3} + 1 \cdot i^{2} + 1 \cdot i + 1 \cdot 1\\ F_{n-1} = 1 \cdot F_{n-1} + 0 \cdot F_{n-2} + 0 \cdot i^{3} + 0 \cdot i^{2} + 0 \cdot i + 0 \cdot 1\\ (i+1)^{3} = 0 \cdot F_{n-1} + 0 \cdot F_{n-2} + 1 \cdot i^{3} + 3 \cdot i^{2} + 3 \cdot i + 1 \cdot 1\\ (i+1)^{2} = 0 \cdot F_{n-1} + 0 \cdot F_{n-2} + 0 \cdot i^{3} + 1 \cdot i^{2} + 2 \cdot i + 1 \cdot 1\\ i+1 = 0 \cdot F_{n-1} + 0 \cdot F_{n-2} + 0 \cdot i^{3} + 0 \cdot i^{2} + 1 \cdot i + 1 \cdot 1\\ 1 = 0 \cdot F_{n-1} + 0 \cdot F_{n-2} + 0 \cdot i^{3} + 0 \cdot i^{2} + 0 \cdot i + 1 \cdot 1 \end{cases} Fn=1Fn1+1Fn2+1i3+1i2+1i+11Fn1=1Fn1+0Fn2+0i3+0i2+0i+01(i+1)3=0Fn1+0Fn2+1i3+3i2+3i+11(i+1)2=0Fn1+0Fn2+0i3+1i2+2i+11i+1=0Fn1+0Fn2+0i3+0i2+1i+111=0Fn1+0Fn2+0i3+0i2+0i+11 = > = > => A = [ 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 ] A = \begin{bmatrix} 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{bmatrix} A=1,1,1,1,1,11,0,0,0,0,00,0,1,3,3,10,0,0,1,2,10,0,0,0,1,10,0,0,0,0,1


[ F n F n − 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 n − 1 F n − 2 i 3 i 2 i 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 ] 2 ⋅ [ F n − 2 F n − 3 ( 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 ] n − 1 ⋅ [ F 1 F 0 2 3 2 2 2 1 ] \begin{bmatrix} F_{n}\\ F_{n-1} \\ (i+1)^{3}\\ (i+1)^{2}\\ i+1\\ 1 \end{bmatrix} = \begin{bmatrix} 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{bmatrix} \cdot \begin{bmatrix}F_{n-1}\\ F_{n-2} \\ i^{3}\\ i^{2}\\ i\\ 1 \end{bmatrix} = \begin{bmatrix} 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{bmatrix}^{2} \cdot \begin{bmatrix}F_{n-2}\\ F_{n-3} \\ (i-1)^{3}\\ (i-1)^{2}\\ i-1\\ 1 \end{bmatrix} = \cdot \cdot \cdot \cdot = \begin{bmatrix} 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{bmatrix}^{n - 1} \cdot \begin{bmatrix}F_{1}\\ F_{0} \\ 2^{3}\\ 2^{2}\\ 2\\ 1 \end{bmatrix} FnFn1(i+1)3(i+1)2i+11=1,1,1,1,1,11,0,0,0,0,00,0,1,3,3,10,0,0,1,2,10,0,0,0,1,10,0,0,0,0,1Fn1Fn2i3i2i1=1,1,1,1,1,11,0,0,0,0,00,0,1,3,3,10,0,0,1,2,10,0,0,0,1,10,0,0,0,0,12Fn2Fn3(i1)3(i1)2i11==1,1,1,1,1,11,0,0,0,0,00,0,1,3,3,10,0,0,1,2,10,0,0,0,1,10,0,0,0,0,1n1F1F0232221


最后求出 A n − 1 A^{n-1} An1后,与公式中最后的行列式相乘即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long LL;
const int mod=1000000007;
const int Max_n=500005;
int x[6]={1,0,8,4,2,1};

struct Mat{
    LL mat[6][6];
};

Mat mul(Mat a,Mat b){
    Mat z;
    for(int i=0;i<6;i++){
        for(int j=0;j<6;j++){
            z.mat[i][j]=0;
            for(int k=0;k<6;k++){
                z.mat[i][j]+=(a.mat[i][k]*b.mat[k][j])%mod;
                z.mat[i][j]%=mod;
            }
        }
    }
    return z;
}
Mat q_pow(Mat a,LL b){
    Mat ans={
        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,1,0,
        0,0,0,0,0,1,
    };
    Mat res=a;
    while(b){
        if(b&1) ans=mul(ans,res);
        res=mul(res,res);
        b>>=1;
    }
    return ans;
}

int main(){
    Mat a={
        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 t;
    scanf("%d",&t);
    while(t--){
        LL n;
        scanf("%lld",&n);
        if(n==1){
            printf("1\n");
            continue;
        }
        if(n==0){
            printf("0\n");
            continue;
        }
        Mat ans=q_pow(a,n-1);
        int res=0;
        for(int i=0;i<6;i++){
            res+=(ans.mat[0][i]*x[i])%mod;
            res%=mod;
        }
        printf("%d\n",res);
    }
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值