浅谈斐波那契数列——从递推到矩阵乘法

本文介绍了一种使用矩阵乘法高效计算斐波那契数列的方法,并通过对比传统递推法,展示了矩阵乘法在计算效率上的优势。

说在前面

相信大家都已经知道这个中外著名的费波纳切数列了吧,关于费波那契数列有很多有趣的性质,但我们这里不讲,在这里我们只是利用斐波那契数列来引出另一个神奇的东西,矩阵乘法,递推在这里是起一个对比与铺垫的作用,(没有对比就不知道矩阵乘法有多快)。

斐波那契数列

定义一个数列

F(n)=0,1Fn1+Fn2,n=0 n=1n2

递推

递推(我当大家都会了),但是这样的做法时间复杂度是O(n),的,当n很大时,这个算法就会T。

通项公式

斐波那契数列有一个通项公式,

F(n)=15×(1+52)n(152))n
,直接用快速幂计算两个log,但是如果要取模怎么办?求一个非整数的逆元?通项公式似乎很难。

进入正题——矩阵乘法

知识预备:
①设

A=[110321]

B=321110

AB=[(1×3+0×2+2×1)(1×3+3×2+1×1)(1×1+0×1+2×0)(1×1+3×1+1×0)]=[5412]

②设
A=[abcd]

B=[ef]

AB=[ae+cfbe+df]

有了这些东西,接下来就可以做斐波那契了,把相邻两项写在一个2*1的矩阵中,
[FnFn1]=[Fn1+Fn2Fn1]=[Fn1×1+Fn2×1Fn1×1+Fn2×0]=[1110]×[Fn1Fn2]=[1110]n1×[F1F0]=[1110]n1×[10]

那么问题的本质,就是如何解决计算这一块
[1110]n1

算完之后,取矩阵第一行第一列的元素,计算这个其实又是快速幂,说些什么呢?谢谢蒙格马利吧。

代码

快速幂:

function f(a,b:extended;n:int64):int64;
var
        t,y:extended;
begin
        t:=1;
        y:=a;
        while b<>0 do
        begin
                if(b and 1)=1 then
                t:=t*y mod n  ;
                y:=y*y mod n;
                b:=b shr 1;
        end;
        exit(t);
end;

用快速幂求出斐波那契的第n项。

type
        matrix=array[0..1,0..1] of int64;
const
        mo=trunc(1e+8+7);
var
    a,ans:array[0..1] of int64;
    b,c,d:matrix;
    i,j,k:longint;
        n:int64;
procedure work(var a,b,c:matrix);//两个2*2的矩阵相乘
var
        i,j,k:longint;
begin
        for i:=0 to 1 do
        begin
                for j:=0 to 1 do
                begin
                        for k:=0 to 1 do
                        begin
                                c[i,j]:=(c[i,j]+a[i,k]*b[k,j] mod mo) mod mo;
                        end;
                end;
        end;
end;
procedure fastpower(x:int64);
begin
        c[0,0]:=1;
    c[0,1]:=1;
    c[1,0]:=1;
        c[1,1]:=0;
    b[0,0]:=1;//开始将B赋值为单位矩阵,相当于实数中1在乘法中的作用
    b[1,1]:=1;
    while x<>0 do
    begin
        if (x and 1)=1 then
        begin
            fillchar(d,sizeof(d),0);
                        work(b,c,d);
                        b:=d;
        end;
        fillchar(d,sizeof(d),0);
                work(c,c,d);
                c:=d;
                x:=x div 2;
    end;
end;
begin
        readln(n);
        if n=0 then
                writeln(0);
        if (n=1)or(n=2) then
                writeln(1);
    fastpower(n-1);
    a[0]:=1;
    a[1]:=0;
    for i:=0 to 1 do
    begin
        for j:=0 to 1 do
        begin
            ans[i]:=(ans[i]+a[j]*b[j][i] mod mo) mod mo;
        end;
    end;
    writeln(ans[0] mod mo);
end.

可以发现其实两者实质上是一样的,只是在计算的时候,一个用矩阵计算,另一个直接用一个变量计算,(矩阵其实也就是一堆变量)。

the end

由于我的水平有限,难免有些会写错的,希望大家多多包容,批评指正,谢谢。

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值