Fibonacci 第 n 项及Fibonacci 前 n 项和

Posted candy067

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fibonacci 第 n 项及Fibonacci 前 n 项和相关的知识,希望对你有一定的参考价值。

这其实是两道题目,但是他们量都题目的思路是在是相像,而且炒鸡厉害。

Fibonacci 第 n 项

题目描述
大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f=3...fn=fn-1+fn-2,
f1=1,f2=1,f3=2,f4=3,…,fn=fn?1+fn?2。
现在问题很简单,输入 n 和 m,求 fn mod m

输入格式
输入 n,m。
输出格式
输出 fn mod m

样例输入
5 1000
样例输出
5

Fibonacci 前 n 项和

题目描述
大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f=3...fn=fn-1+fn-2,
f1=1,f2=1,f3=2,f4=3,…,fn=fn?1+fn?2。
现在问题很简单,输入 n 和 m,求 fn的前n项sn mod m

输入格式
输入 n,m。
输出格式
输出 fn mod m

样例输入
5 1000
样例输出
12

这两个的数据都是很惊人,都是$$n<=2*10^9$$
有木有一种恐怖袭击的来临,很显然我们不能用传统的思想来,因为数组根本存不下,要不然我写这个有什么意思
所以这里就要用到矩阵乘法
切入正题,核核。首先是Fibonacci 第 n 项这道题,我们可以知道:

f[i]=1*f[i-1]+1*f[i-2]
f[i-1]=1*f[i-1]+0*f[i-2]

把他们看成一个矩阵,转换为
$$
\beginpmatrix
f[i] \
f[i-1]
\endpmatrix
=\beginpmatrix
1 & 1 \
1 & 0
\endpmatrix*
\beginpmatrix
f[i-1] \
f[i-2]
\endpmatrix
$$
因为

f[i]=1*f[i-1]+1*f[i-2]
f[i-1]=1*f[i-1]+0*f[i-2]

所以可以根据矩阵乘法(我默认你矩阵乘法懂了 )得出刚刚的那个矩阵
接着我们又可以得到:
$$
\beginpmatrix
f[i] \
f[i-1]
\endpmatrix
=\beginpmatrix
1 & 1 \
1 & 0
\endpmatrix
\beginpmatrix
1 & 1 \
1 & 0
\endpmatrix

\beginpmatrix
f[i-2] \
f[i-3]
\endpmatrix
$$
然后这样一直化简,可以得出一般式
$$
\beginpmatrix
f[i] \
f[i-1]
\endpmatrix
=\beginpmatrix
1 & 1 \
1 & 0
\endpmatrix^n-2
\beginpmatrix
f[2] \
f[1]
\endpmatrix
$$
然后因为矩阵可以用乘法结合律,所以我们可以用快速幂,把
$$
\beginpmatrix
1 & 1 \
1 & 0
\endpmatrix
$$
看成是一个数x,那么我们就可以用快速幂去求$$x^n-2$$的值啦。大大减少了空间有木有【0_0】

然后上代码(我都说的这么清楚了还用得着看代码?!

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef signed long long ll;
struct node

    ll p[3][3];
    node()memset(p,0,sizeof(p));
;
int n;
ll M;
node A;
node plus(node a,node b)

    node c;
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
            for(int k=1;k<=2;k++)
                c.p[i][j]+=a.p[i][k]*b.p[k][j],c.p[i][j]%=M;
    return c;

node plus1(node a,node b,int n,int m,int p)

    node c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=p;j++)
            for(int k=1;k<=m;k++)
                c.p[i][j]+=a.p[i][k]*b.p[k][j],c.p[i][j]%=M;
    return c;

node mi(int n)//快速幂运算,也可以用while,因为这个有可能会爆栈

    if(n==1)return A;
    node t=mi(n/2);
    if(n%2==1)return plus(plus(t,t),A);
    else return plus(t,t);

int main()

    A.p[1][1]=1;A.p[1][2]=1;
    A.p[2][1]=1;A.p[2][2]=0;
    scanf("%d %llu",&n,&M);
    node c=mi(n-2),ha;//矩阵的幂运算
    ha.p[1][1]=1;ha.p[2][1]=1;//因为f[1]=f[2]=1,这是题目给出的
    c=plus1(c,ha,2,2,1);
    printf("%llu\n",c.p[1][1]%M);
    return 0;

然后下一题跟这一题目的思路很像,因为题目说s[i]=f[i]前i项的和,所以可以得出:

//这里我们用s[n-1],f[n],f[n-1]来表示这s[n],f[n+1],f[n]
s[n]=1*s[n-1]+1*f[n]+0*f[n-1]
//因为s[n]是前n个肥波数列的前缀和,所以他就是前n-1的前缀和加上第n个肥波数列
f[n+1]=0*s[n-1]+1*f[n]+1*f[n-1]
//那第n项的下一个就是f[n]+f[n-1]
f[n]=0*s[n-1]+1*f[n]+0*f[n-1]
//f[n]就为f[n]
//这样我们就建立起了关系

这种思路很好理解,但很难想哎!
然后像上一题一样把他换成矩阵,就得
$$
\beginpmatrix
s[n] \
f[n+1] \
f[n]
\endpmatrix=
\beginpmatrix
1 & 1 & 0 \
0 & 1 & 1 \
0 & 1 & 0
\endpmatrix*
\beginpmatrix
s[n-1] \
f[n] \
f[n-1]
\endpmatrix
$$
然后可以一直化简到一般式
$$
\beginpmatrix
s[n] \
f[n+1] \
f[n]
\endpmatrix=
\beginpmatrix
1 & 1 & 0 \
0 & 1 & 1 \
0 & 1 & 0
\endpmatrix^n-1
\beginpmatrix
s[1] \
f[2] \
f[1]
\endpmatrix
$$
一样的思路,上代码!

#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef signed long long ll;
struct node

    ll p[4][4];
    node()memset(p,0,sizeof(p));
;
int n;
ll M;
node A;
node plus(node a,node b)

    node c;
    for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++)
            for(int k=1;k<=3;k++)
                c.p[i][j]+=a.p[i][k]*b.p[k][j],c.p[i][j]%=M;
    return c;

node plus1(node a,node b,int n,int m,int p)

    node c;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=p;j++)
            for(int k=1;k<=m;k++)
                c.p[i][j]+=a.p[i][k]*b.p[k][j],c.p[i][j]%=M;
    return c;

node mi(int n)

    if(n==1)return A;
    node t=mi(n/2);
    if(n%2==1)return plus(plus(t,t),A);
    else return plus(t,t);

int main()

    A.p[1][1]=1;A.p[1][2]=1;A.p[1][3]=0;
    A.p[2][1]=0;A.p[2][2]=1;A.p[2][3]=1;
    A.p[3][1]=0;A.p[3][2]=1;A.p[3][3]=0;
    scanf("%d %llu",&n,&M);
    node c=mi(n-1),ha;
    ha.p[1][1]=1;ha.p[2][1]=1;ha.p[3][1]=1;
    c=plus1(c,ha,3,3,1);
    printf("%llu\n",c.p[1][1]%M);
    return 0;

总结:矩阵乘法大大压缩了空间

本文思路摘自《一本通提高篇》

以上是关于Fibonacci 第 n 项及Fibonacci 前 n 项和的主要内容,如果未能解决你的问题,请参考以下文章

一个差生解1642Fibonacci 第 n 项

Fibonacci数

第4章-6.输出前 n 个Fibonacci数 (15分)

c问题,fibonacci数列.

1. Fibonacci数列。Fibonacci数列的计算公式如下:

Fibonacci数列--矩阵乘法优化