斐波那契数列--计算前后缀

hdu3117

求[0,1e8]的F(n)的前后4位。

输入:

35
36
37
38
39
40
64
65
输出:

9227465
14930352
24157817
39088169
63245986
1023...4155
1061...7723
1716...7565

1.斐波那契数列前4位的计算

通项公式 f[n]=(1/sqrt(5)) * { [(1 + sqrt(5)) / 2] ^ n - [(1 - sqrt(5)) / 2]^ n }

减号后面的部分,底数小于1,当n增大时,非常小,可以忽略。

F(n),对10取对数,得double lg = -0.5 * log10(5.0) + n * log10(gold);

直接再对10取幂貌似超时。

因为10对0.b次方等于10对a.b次方向右移a位,数字不变,所以可以

    lg -= (int)lg;

    double fn =pow(10,lg);

再使fn成为4位数。

2.斐波那契数列对mod取余的计算

f(1)=1,f(2)=2,f(n)=f(n-1)+f(n-2)(n>=3)

   用矩阵表示为:


    


可用矩阵快速幂取模求解。


#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

using namespace std;

const int maxn = 40;

const double gold = (1 + sqrt(5.0)) / 2;

long long f[maxn] = {0,1};

struct martrix{

    int a[2][2] = {{1,0},{0,1}};

};


martrix multiply(martrix &a,martrix &b,int n)

{

    martrix res;

    memset(res.a,0,sizeof(res.a));

    for (int i = 0; i < n; i ++) {

        for (int j = 0; j < n; j ++) {

            for (int k = 0; k < n; k ++) {

                res.a[i][j] += a.a[i][k] * b.a[k][j];

            }

            res.a[i][j] %= 10000;

        }

    }

    return res;

}

void prefix(int n)

{

    double lg = -0.5 * log10(5.0) + n * log10(gold);

    lg -= (int)lg;

    double fn = pow(10,lg);

    while(fn < 1000) fn *= 10;

    printf("%d...",(int)fn);

}

void suffix(int k)

{

    martrix res,q;

    q.a[0][1] = 1;q.a[1][0] = 1;q.a[1][1] = 0;

    while(k)

    {

    if (k & 1) {

        res = multiply(res, q, 2);

    }

    k >>= 1;

    q = multiply(q, q, 2);

   }

    int fn = res.a[0][0] + res.a[0][1];

    printf("%04d\n",fn % 10000);

   

}

int main()

{

    for(int i = 2;i < maxn;i ++) f[i] = f[i - 1] + f[i - 2];

    int n;

    while(scanf("%d",&n) != EOF)

    {

        if (n < maxn) {

            printf("%lld\n",f[n]);

        }

        else {

            prefix(n);

            suffix(n - 2);

        }

    }

    return 0;

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值