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 项和的主要内容,如果未能解决你的问题,请参考以下文章