说到斐波那契数列,相信大家都不陌生
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 一下循环节就好了。
嗯。
关于斐波那契目前能想到的就这些了,