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

来源:互联网 发布:淘宝美工班 编辑:程序博客网 时间:2024/05/29 10:44

hdu3117

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

输入:

3536373839406465
输出:

9227465149303522415781739088169632459861023...41551061...77231716...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 namespacestd;

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);

        }

    }

    return0;

}