POJ - 3070 Fibonacci(快速幂的优化---矩阵快速幂)

本文介绍了一种高效求解斐波那契数列第n项最后四位数的方法,通过矩阵快速幂算法避免了直接递归或迭代带来的效率问题。详细解释了如何构造特定矩阵以及实现矩阵乘法和快速幂运算,最终达到O(logn)的时间复杂度。
摘要由CSDN通过智能技术生成

题目链接https://vjudge.net/contest/328717#problem/F
在这里插入图片描述
题意
求斐波那契数列的第n项的最后四位数( 0 ≤ n ≤ 1,000,000,000),
注意对于每个测试用例,打印f[n]的最后四位数字。如果f[n]的最后四位数都是零,则打印“0”;否则,省略任何前导零(即打印f[n] mod 10000)。

引入矩阵的概念
在这里插入图片描述
单位矩阵
矩阵的左上角到右下角上的元素都为1,除此以外,矩阵中的元素全部为0。
单位矩阵*任何矩阵=矩阵的本身。
在这里插入图片描述
在这里插入图片描述
矩阵快速幂算法
假如现在有一个n * n的方阵A。所谓方阵就是行数和列数相等的矩阵,先给出一个数M,让算矩阵A的M次幂。

struct Matrix
{
    int mp[maxn][maxn];
} ans,res;
Matrix Mul( Matrix A, Matrix B)
{
    Matrix temp;/*定义一个临时矩阵,存放A*B的结果*/
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            temp.mp[i][j]=0;
            for(int k=1; k<=n; k++)
                temp.mp[i][j]+=A.mp[i][k]*B.mp[k][j];
        }
    }
    return temp;
}
void QuickPower(int N)
{
    /*整数的快速幂ans初始化为1,
    对于矩阵的乘法来说,ans应该初始化为单位矩阵,
    对于单位矩阵E,任何矩阵A*E=A*/
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)
        {
            if(i==j)
                ans.mp[i][j]=1;
            else
                ans.mp[i][j]=0;
        }
    while(N)
    {
        if(N&1)
            ans=Mul(ans,res);
        res=Mul(res,res);
        N=N>>1;
    }
}

赋予矩阵快速幂意义
观察f[n] = f[n-1]+f[n-2] 第n项是由第n-1项和第n-2项递推而来。
同理,第n+1项由第n项和第n-1项递推而来。
在这里插入图片描述
f[n-1]、f[n-2]则乘上左方矩阵,就能得到等号左侧矩阵,第一个位置
即为要求的f[n]。

完整代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
int n;
struct node
{
    int mp[3][3];
} first,behid;
node solve(node x,node y)
{
    node temp;
    for(int i=1; i<=2; i++)
    {
        for(int j=1; j<=2; j++)
        {
            temp.mp[i][j]=0;
            for(int k=1; k<=2; k++)
            {
                temp.mp[i][j]+=(x.mp[i][k]*y.mp[k][j]);
                temp.mp[i][j]%=10000;
            }
        }
    }
    return temp;
}
int Quick_Mi(int n)
{
    for(int i=1; i<=2; i++)/*初始化为单位矩阵*/
        for(int j=1; j<=2; j++)
        {
            if(i==j)
                first.mp[i][j]=1;
            else
                first.mp[i][j]=0;
        }
    behid.mp[1][1]=1;
    behid.mp[1][2]=1;
    behid.mp[2][1]=1;
    behid.mp[2][2]=0;/*为斐波那契创造的矩阵*/
    while(n)
    {
        if(n&1)
            first=solve(first,behid);
        behid=solve(behid,behid);
        n>>=1;
    }
    return first.mp[1][2];
}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==-1)
            break;
        int ans=Quick_Mi(n);
        printf("%d\n",ans);
    }
    return 0;
}

参考博客:https://www.cnblogs.com/cmmdc/p/6936196.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zaiyang遇见

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值