Fibonacci的4种变式

基础题:求大项斐波那契:

题目:Fibonacci

分析:

当代计算机计算量1s大约1e7

复杂度数量级最大规模
O ( log ⁡ N ) O\left( \log N\right) O(logN) 1 0 20 10^{20} 1020很大
O ( N ) O\left( \sqrt {N}\right) O(N ) 1 0 12 10^{12} 1012 1 0 14 10^{14} 1014
O ( N ) O\left( N\right) O(N) 1 0 6 10^{6} 106 1 0 7 10^{7} 107
O ( N log ⁡ N ) O\left( N\log N\right) O(NlogN) 1 0 5 10^{5} 105 1 0 6 10^{6} 106
O ( N 2 ) O\left( N^{2}\right) O(N2)10002500
O ( N 3 ) O\left( N^{3}\right) O(N3)100500
O ( N 4 ) O\left( N^{4}\right) O(N4)5050
O ( 2 N ) O\left( 2^{N}\right) O(2N)2020
O ( 3 N ) O\left( 3^{N}\right) O(3N)1415
O ( N ! ) O\left( N!\right) O(N!)910

常用算法:

时间复杂度算法举例
O ( log ⁡ N ) O\left( \log N\right) O(logN)快速幂,数位dp
O ( N ) O\left( N\right) O(N)KMP,欧拉筛法
O ( N log ⁡ N ) O\left( N\log N\right) O(NlogN)线段树
O ( N 2 ) O\left( N^{2}\right) O(N2)某些dp
O ( N 3 ) O\left( N^{3}\right) O(N3)匈牙利算法
O ( 2 N ) O\left( 2^{N}\right) O(2N)二进制枚举
O ( N ! ) O\left( N!\right) O(N!)爆搜

无疑问1e9>1e7而且差距较大,常规 O ( n ) O(n) O(n)算法会爆掉,(斐波那契数列的项数n一旦过大,就要考虑快速幂,普通算法时间空间都开销太大)因此题没给出数据组数范围,可选择不储存数列各项来试水,果然ac,矩阵快速幂求解即可

代码:

#include<bits/stdc++.h>
#define fo(i,a,b) for(long long i=a;i<b;i++)
//#define M 1e4错误示范 
#define M 10000
#define LL long long
using namespace std;
LL n;
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;
LL init(){
    cin>>n;
    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;//别忘记清零
    return n;
}
int main(){
    while(init()>=0){
        for (LL i=n;i;i>>=1,o=o*o) if (i&1) t = t*o;//快速幂
        printf( "%lld\n", t.a[0][1]%M );
    }
    return 0;
}

需要注意:

  • 取余题目数据一般用:long long
  • 要用sizeof(r.a),不要用16,因为是long long 的前提
  • 多次用t,o矩阵,自然别忘清零
  • 因为我们经常求的是特殊矩阵的n次方,所以一般是结果的F[0][0]为Fn+1,F[1][0]为Fn

变式一:Fibonacci 前 n 项和

题目: Fibonacci 前 n 项和

核心公式: S n = f n + 2 − 1 S_{n}=f_{n+2}-1 Sn=fn+21
详细推导方法请参考:斐波那契数列的前N项和

解决思路: 求出n+2次幂来,减去1即可


变式二:类斐波那契数列1

题目:佳佳的 Fibonacci

思路:

能否像变式一样简单的求出一个 S n S_{n} Sn表达式,仅以 f n f_{n} fn为变量呢?

核心公式:
T n = n f n + 2 − f n + 3 + 2 T_{n}=nf_{n+2}-f_{n+3}+2 Tn=nfn+2fn+3+2
推导过程:(受louhc指点)
在这里插入图片描述

解决思路:

多求两项就可以了,但是本题还有其他解法,当二维公式比较难推出时,同样也可以构造三维或四维方阵,有兴趣参考大佬代码:四维方阵解法


变式三:斐波那契平方和

题目:#6264. friend-斐波那契

题意:
在这里插入图片描述
核心公式:
∑ a n 2 = a n a n + 1 \sum a^{2}_{n}=a_{n}a_{n+1} an2=anan+1
推导:

代码:

#include<string.h>
#include<stdio.h>
#define ll long long
#define MOD 1000000007
struct nobe{ll a[2][2];nobe(){memset(a,0,sizeof(a));} };
ll n;
ll sum;
nobe mut(nobe x,nobe y){
    nobe res;
    for(ll i=0;i<2;i++)for( int j=0;j<2;j++)for( int k=0;k<2;k++)
        res.a[i][j]=(res.a[i][j]+x.a[i][k]*y.a[k][j])%MOD;
    return res;
}//2-2矩阵乘法
void quick(ll n){
    nobe c,res;
    c.a[0][0]=c.a[0][1]=c.a[1][0]=1;
    c.a[1][1]=0;
    for(int i=0;i<2;i++) res.a[i][i]=1;
    while(n)
    {  
        if(n&1)res=mut(res,c);
        c=mut(c,c);
        n=n>>1;    
    }//F(0)=0,F(1)=1,F(2)=1且res矩阵每个数都会变化,没有规律   
    printf("%lld\n",(res.a[0][0]%MOD)*(res.a[1][0]%MOD)%MOD);//这是对的 
}
int main(){
    while(scanf("%lld",&n)!=EOF)
        quick(n);
    return 0;
}


变式四:类斐波那契数列2

题目:又见斐波那契

思路:
在这里插入图片描述

ac代码:

#include<bits/stdc++.h>
#define fo(i,a,b) for(long long i=a;i<b;i++)
//#define M 1e4错误示范 
#define M 1000000007
#define LL long long
using namespace std;
LL n;
struct mat{
    LL a[6][6];
    mat operator*(mat t){
        mat r; memset(r.a,0,sizeof(r.a));
        fo(i,0,6)fo(k,0,6)fo(j,0,6)
            r.a[i][j]=(r.a[i][j] +1ll*a[i][k]*t.a[k][j])%M;
        return r;
    }//矩阵结构体里重载矩阵乘法 
}o,t;
void init(){
    cin>>n;
    memset(t.a,0,sizeof(t.a));
    memset(o.a,0,sizeof(o.a));//此处少了分号会有奇怪的报错 
    fo(i,0,6) t.a[i][i]=1;
    o.a[0][0] = 1; o.a[0][1] = 1; o.a[0][2] = 1; o.a[0][3] = 4; o.a[0][4] = 6; o.a[0][5] = 4;
    o.a[1][0] = 1;
    o.a[2][2] = 1; o.a[2][3] = 3; o.a[2][4] = 3; o.a[2][5] = 1;
    o.a[3][3] = 1; o.a[3][4] = 2; o.a[3][5] = 1;
    o.a[4][4] = 1; o.a[4][5] = 1;
    o.a[5][5] = 1;
}
int main(){
    int c;cin>>c;
    while(c--){
        init();
        for (LL i=n;i;i>>=1,o=o*o) if (i&1) t = t*o;//快速幂
        LL ans = 0;
        for ( int i = 0 ; i < 6 ; ++ i ) {
            if ( i == 1 ) continue;
            ans = (ans+t.a[1][i])%M;
        }
        printf( "%lld\n", ans );
    }
    return 0;
}

本blog暂时结束(将来可能更新)

最后列出本blog部分参考的大佬文章:

orz:louhc:变式二

斐波那契数列平方求和

加强版斐波那契数列(矩阵快速幂)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值