Fibonacci Numbers公式推导(数论)

题目:Fibonacci Numbers

简介: 如果斐波那契数小于8位的就输出这个数,大于8位的就输出前四位,以及后四位

公式部分:

Fibonacci求和公式:
F ( n ) = 1 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] ( a 0 = 0 , a 1 = 1 ) \begin{aligned}F\left( n\right)=\dfrac {1}{\sqrt {5}}\left[ \left( \dfrac {1+\sqrt {5}}{2}\right) ^{n}-\left( \dfrac {1-\sqrt {5}}{2}\right) ^{n}\right] \\ \left( a_{0}=0,a_{1}=1\right) \end{aligned} F(n)=5 1[(21+5 )n(215 )n](a0=0,a1=1)

我们将两边取对数,其中当n够大时,以下式子无限接近于0,所以可以省略:
lim ⁡ n > 40 lg ⁡ ( 1 − 5 2 ) n → 0 \lim _{n>40}\lg\left( \dfrac {1-\sqrt {5}}{2}\right) ^{n}\rightarrow 0 n>40limlg(215 )n0
最终得到如下公式
l g F ( n ) = x + n y ( x = lg ⁡ 1 5 , y = lg ⁡ 1 + 5 2 ) \begin{aligned}lgF\left( n\right) =x+ny\\ \left( x=\lg \dfrac {1}{\sqrt {5}},y=\lg \dfrac {1+\sqrt {5}}{2}\right) \end{aligned} lgF(n)=x+ny(x=lg5 1,y=lg21+5 )
我们用这个公式解决当n>=40时数列前四位的问题

题目分析:

  • 通过打表可以发现到39位为止都不超过8位数,当n>39时再分别求前四位和后四位
  • 后四位矩阵快速幂求解
  • l g F ( n ) = a lgF\left( n\right)=a lgF(n)=a,当我们求出a时,只需要通过 a = a − ⌊ a ⌋ a=a-\lfloor a\rfloor a=aa求出a的小数部分,之后 1 0 a × 1 e 3 10^{a}\times 1e3 10a×1e3即可得到 F ( n ) F\left( n\right) F(n)的前四位(整数部分只是贡献结果末尾的0罢了)

代码:

#include<stdio.h>
#include<math.h>
#include<string.h>
#define LL long long
#define fo(i,a,b) for(int i=a;i<b;i++)
int fib[40] = {0, 1};
const double x = log10(1.0 / sqrt(5.0));
const double y = log10((1.0 + sqrt(5.0)) / 2.0);
const int M=1e4;
struct mat{
    LL a[2][2];
    mat operator*(mat t){
        mat r; memset(r.a,0,sizeof(r.a));
        fo(i,0,2)fo(k,0,2)fo(j,0,2)
            r.a[i][j]=(r.a[i][j] +1ll*a[i][k]*t.a[k][j])%M;
        return r;
    }//重载矩阵乘法
}o,t;
void init(){
    t.a[0][0] = t.a[1][1] = 1;  t.a[0][1] = t.a[1][0] = 0;//别忘记清零
    o.a[0][0] = o.a[1][0] = o.a[0][1] = 1;  o.a[1][1] = 0;//别忘记清零
}
int main(){
    int n,i,b;
    double a;
    for(i = 2; i < 40; ++i) fib[i] = fib[i-1] + fib[i-2];
    while(scanf("%d",&n)==1){
        init(); 
        if(n < 40) printf("%d\n", fib[n]);
        else{
            a=x+n*y;
            a-=(int)a;//整数部分最后是一堆0,丢掉即可 
            a=pow(10,a);
            for (LL i=n;i;i>>=1,o=o*o)if(i&1)t=t*o;//快速幂
            printf("%d...%0.4d\n", (int)(a*1000),t.a[0][1]%M);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值