【我恨数论】之 斐波那契数列

3 篇文章 0 订阅

说到斐波那契数列,相信大家都不陌生
0 1 1 2 3 5 8 13 21
递推公式为
f[n]=f[n-1]+f[n-2];
首先来分析一下斐波那契的某些性质;
因为 第 n 项 为 第 n-1 项和n-2 项的和。
同时考虑三角形的三边
任意两边之和大于第三边
所以,如果要在1-n中选出尽可能多的数,使这些数之间都不能组成三角形。
那么
最优的情况就是斐波那契数列
因为斐波那契里的每一项都恰好等于前两项和
恰好不能组成三角形

那么怎么求斐波那契
随便想想都知道,斐波那契数列的增速是非常快的
所以我们一般都要对它取模
f[n]=f[n-1]+f[n-2]
利用递推公式可以求前1亿个左右
那么
很明显是很慢的
怎去优化时间?
矩阵!!

利用矩阵乘法我们可以在logn的时间内求斐波那契
公式如下:
f[n] ············ 1··· 1············f[n-1]
·············=[·············· ] * [ ·············· ]
f[n-1]········· 1···· 0 ···········f[n-2]
(忽略省略号)
手推可知公式的正确性
所以 要求f[n]
只需要知道 f[1] f[2]和这个转换矩阵的n-1次方即可
怎么求n-1次方??
快速幂!!!

代码:

struct zqm //矩阵
{
    unsigned long long a[3][3];
}k;
zqm c(zqm x,zqm y)//定义矩阵乘法
{
    zqm an;
    an.a[1][1]=(x.a[1][1]*y.a[1][1]%p+x.a[1][2]*y.a[2][1]%p)%p;
    an.a[1][2]=(x.a[1][1]*y.a[1][2]%p+x.a[1][2]*y.a[2][2]%p)%p;
    an.a[2][1]=(x.a[2][1]*y.a[1][1]%p+x.a[2][2]*y.a[2][1]%p)%p;
    an.a[2][2]=(x.a[2][1]*y.a[1][2]%p+x.a[2][2]*y.a[2][2]%p)%p;
    return an;
}
zqm ksm(unsigned long long m) //矩阵快速幂
{
    zqm ans=k;
    zqm nx=k;
    for(;m;nx=c(nx,nx),m>>=1)
    {
        if(m & 1)
        {
            ans=c(ans,nx);
        }
    }
    return ans;
}
unsigned long long fe(int x)//求斐波那契数列的第X项
{
    if(x==0)return 0;
    if(x==1)return 1;
    if(x==2)return 1;
    if(x==3)return 2;
    zqm qw;
    qw=ksm(x-3);
    return (qw.a[1][1]+qw.a[1][2])%p; 
}

那么,当要求的n超过10^9怎么做呢?
循环节!
因为肯定要对某个数取模
所以,手写一个暴力程序去寻找循环节
只要找到了 0 1 之后
后面的肯定为循环部分
因为斐波那契的某一项之和他之前的两项有关
和其他无关。
所以只需要对这个巨大的n mod 一下循环节就好了。

嗯。
关于斐波那契目前能想到的就这些了,

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值