简单的说就是f[n]=f[n-1]+f[n-2],f[1]=1,f[2]=1的一个数列。
1.根据递推式可以简单得出一个递归求法。
typedef long long ll; ll f(ll x){ if(x==1||x==2)return 1; else return f(x-1)+f(x-2); } int main(){ ll n; scanf("%lld",&n); printf("%lld\n",f(n)); }
2.显然得出这样得一个递归式子出现了大量得重复计算,可以记忆化优化
typedef long long ll; const int maxn=50; ll f[maxn]; int main(){ ll n; f[1]=f[2]=1; scanf("%lld",&n); for(int i=3;i<=n;i++){ f[i]=f[i-1]+f[i-2]; } printf("%lld\n",f[n]); }
3.如果可以构造如图所示的矩阵,那么连续给矩阵乘以n个这样的矩阵就可以得到f。
又因为矩阵满足结合律,所以可以用快速幂的方式,除去矩阵乘法的时间复杂度,O(logn)就可以得到斐波那契数列的第n项。
对于常系数线性齐次递推得到如下结论:
const int N=10,M=10; long long a[10]; long long f[10]; struct matrix{ int n,m; long long a[N][M]; matrix(){// 初始化2*2的单位矩阵 n=m=2; for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ a[i][j]=0; } } for(int i=0;i<n;i++){ a[i][i]=1; } } void clear(){ //memset(a,0,sizeof(a)); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ a[i][j]=0; } } } matrix operator+(const matrix &b)const{ matrix tmp; tmp.clear(); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ tmp.a[i][j]=a[i][j]+b.a[i][j]; } } return tmp; } matrix operator*(const matrix &b)const{ matrix tmp; tmp.clear(); for(int i=0;i<n;i++){ for(int j=0;j<b.m;j++){ for(int k=0;k<m;k++){ tmp.a[i][j]=((a[i][k]*b.a[k][j])+tmp.a[i][j]); } } } return tmp; } }; matrix pow2(matrix A,int n){ matrix B; while(n>0){ if(n&1)B=B*A; A=A*A; n/=2; } return B; } long long solve(long long a[],long long f[],int n,int m){ matrix A,B; A.clear(); B.clear(); A.n=B.n=n; A.m=n; B.m=1; for(int i=0;i<n-1;i++){ A.a[i+1][i]=1; } for(int i=0;i<n;i++){ B.a[i][0]=f[n-i-1]; A.a[0][i]=a[n-i-1]; } A=pow2(A,m); B=A*B; return B.a[n-1][0]; } int main(){//求斐波那契数列第m项 a[0]=1,a[1]=1; //系数 f[0]=0,f[1]=1; //前n项 int m; scanf("%d",&m); printf("%lld\n",solve(a,f,2,m)); return 0; }
4.模素数下求类斐波那契数得第n项(2019南昌网络赛 H. The Nth Item)
题意:Q个询问,每次求F(N),但是N要用上一次询问的结果得到,结果mod998244353。
由待定系数法构造等比数列,求得F(n)=1/sqrt(17)*[((3+sqrt(17))/2)^n-((3-sqrt(17))/2)^n]。发现式子中有根号,要做得就是找到一个可以代替根号17得数,也就是17的二次剩余。
例如本题(2019南昌网络赛 H. The Nth Item)。假设二次剩余为x,那么公式里的全部sqrt(17)都可以换为x。F(n)=1/x*[((3+x)/2)^n-((3-x)/2)^n]。
对于一个数x,求(x^n)%p,显然可以用欧拉定理降幂为x^(n%phi(p)+phi(p)),本题p=998244353,那么指数n最大便为:1996488703。我们可以分块预处理,设N=sqrt(1996488703),把X[0]=x^0,X[1]=x^1,...,X[n]=x^N预处理出来,再把pre[0]=x^(0*N),pre[1]=x^(1*N),...,pre[N]=x^(N*N))。
求出来,这样对于一个询问n=a*N+b,我们其实就是求 (x^(a*N))*(x^b),即pre[a]*X[b]=pre[n/N]*X[n%N]。
using namespace std; const int N = 5e4; const ll mod = 998244353; const ll inv17 = 438914993;//sqrt(17)的二次剩余 const ll x1 = 736044383;//(3+sqrt(17))/2 const ll x2 = 262199973;//(3-sqrt(17))/2 ll X1[N+10],X2[N+10],pre1[N+10],pre2[N+10]; ll ans,n,q,nn,res; ll mo(ll x){ return x>=mod?x%mod:x; } void Init(){ pre1[0]=pre2[0]=X1[0]=X2[0]=1; for(int i=1;i<=N;i++) X1[i]=mo(X1[i-1]*x1),X2[i]=mo(X2[i-1]*x2); for(int i=1;i<=N;i++) pre1[i]=mo(pre1[i-1]*X1[N]),pre2[i]=mo(pre2[i-1]*X2[N]); } int main(){ Init(); scanf("%lld%lld",&q,&n); res=ans=0; while(q--){ n^=(res*res); nn=n%(mod-1)+mod-1; res=mo(pre1[nn/N]*X1[nn%N])-mo(pre2[nn/N]*X2[nn%N]); res=mo(res+mod); res=mo(res*inv17); ans^=res; } printf("%lld\n",ans); return 0; }
5.斐波那契数列又称为黄金分割数列
当n趋向于无穷大时,前一项与后一项的比值越来越逼近黄金分割0.618(或者说后一项与前一项的比值小数部分越来越逼近0.618)。
6.斐波那契数与杨辉三角
7.其他公式
奇数项求和:
偶数项求和:
前n项求和:f-1
平方求和: (值得一提的是这个公式也说明了用斐波那契数的前n项为边长的n个正方形可以构造出一个矩形)
隔项关系:
f(2n-2m-2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n-2m) [ n〉m≥-1,且n≥1]两倍项关系:f(2n)/f(n)=f(n-1)+f(n+1)
其他公式:
当且仅当,n%4==0时,f[n]%3==0等等。。。。。。