hdu 3117 斐波那契数列+矩阵快速幂

题目概括

求第n个斐波那契数。这个n可以很大(10^8)。输出的时候,如果数字不足9位,则输出该数字;否则输出该数字的头四位和尾四位。

思路

参考了这位大佬的输出前四位部分(不是一般的尴尬)https://blog.csdn.net/qq_45034708/article/details/107790982

好吧,先说说前四位。我们可以直接用下面这个公式
(感谢百度)
感谢百度
怎么用呢?因为当n很大,后面那项直接忽略,前面那项又太大了,所以我们取一个对数(log10),用double存起来。
然后,这个数的小数部分取出来(记为coef)。
最后1000*10^coef,解决问题。

再说后面那四位。由于n太大,所以肯定是矩阵快速幂解决(因为我们有矩阵形式的递推公式)。这里面比较套路。要注意的是,long long 显然是存不下那么大的数字的,所以要取模(我取的是10^9)

代码

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn=2;
const ll inf=1e9;
struct Matrix///不想用指针数组传递二维矩阵就可以这么做
{
    ll matrix[maxn][maxn];
    Matrix()
    {
        memset(matrix,0,sizeof(matrix));///好的构造函数
    }
};

Matrix mul(Matrix a,Matrix b)
{
    Matrix res;
    int i,j,k;
    for(i=0;i<maxn;i++)
    {
        for(j=0;j<maxn;j++)
        {
            for(k=0;k<maxn;k++)
            {
                res.matrix[i][j]+=a.matrix[i][k]*b.matrix[k][j];
                res.matrix[i][j]%=inf;
            }
        }
    }
    return res;
}

Matrix quick_mul(Matrix a,int n)
{
    Matrix res;
    int i;
    for(i=0;i<maxn;i++)
    {
        res.matrix[i][i]=1;
    }
    while(n)
    {
        if(n&1) res=mul(res,a);
        a=mul(a,a);
        n>>=1;
    }

    return res;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        if(!n)
        {
            printf("0\n");continue;
        }
        if(n==1)
        {
            printf("1\n");continue;
        }
        Matrix a;
        a.matrix[0][0]=1,a.matrix[0][1]=1,a.matrix[1][0]=1,a.matrix[1][1]=0;
        a=quick_mul(a,n-1);
        if(n<40) printf("%lld\n",a.matrix[0][0]);
        else
        {
            double coef=log10(1.0/sqrt(5.0))+(double)n*log10((1.0+sqrt(5.0))/2.0);
            coef=coef-(int)coef;
            printf("%d", (int)(1000.0 * pow(10.0, coef)));///照搬大佬代码
            printf("...");
            printf("%04d\n",a.matrix[0][0]%10000);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值