斐波拉契数列
斐波拉契数列又称为“兔子数列”,是一些列这样的数形成的数列:1、1、2、3、5、8、13、21、34、……其递推规律如下:
{ F [ n ] = 1 ( n < = 2 ) F [ n ] = F [ n − 1 ] + F [ n − 2 ] ( n > 2 ) \begin{cases} F[n]=1 \ (n<=2)\\ F[n]=F[n-1]+F[n-2] \ (n>2) \\ \end{cases} {F[n]=1 (n<=2)F[n]=F[n−1]+F[n−2] (n>2)
由以上的递推关系,我们很快就能求得第N项斐波拉契数:
int fib(int n){
if(n<=2) return 1;
else return fib(n-1)+fib(n-2);
}
但由于递归频繁调用栈,并且会多次重复计算,我们可以用递推方式来求:
int a=1,b=1,c=1;
for(int i=3;i<=n;i++){
c=a+b;
b=a;
a=c;
}
//数组存储
int a[maxn];
a[1]=1,a[2]=1;
for(int i=3;i<=n;i++){
a[i]=a[i-1]+a[i-2];
}
这两种斐波拉契数列的时间复杂度都是O(n),对于一些较小的数比较实用,但对于特别大的数,这种方法就会超时。
对于较大的数(>1e9)我们可以使用矩阵快速幂来求解。
(图片来源:https://blog.csdn.net/yhl1999/article/details/80994267)
了解了这些,我们来看一道题:传送门
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<list>
#include<cmath>
#include<algorithm>
#define lson node<<1,st,mid
#define rson node<<1|1,mid+1,ed
#define mem(a,x) memset(a,x,sizeof(a))
#define me(a) memset(a,0,sizeof(a))
#define IOS ios::sync_with_stdio(false)
#define lowbit(x) x&(-x)
#define up(i,x,y) for(long long i=x;i<y;i++)
#define down(i,x,y) for(long long i=x;i>=y;i--)
#define in freopen("in.txt","r",stdin)
#define out freopen("out.txt","w",stdout)
typedef long long ll;
const ll mod = 1e9 + 7;
const ll INF = 0x3f3f3f3f;
const int maxn = 1000005;
const double pi = acos(-1.0);
using namespace std;
ll qpow(ll a, ll b) { ll s = 1; while (b > 0) { if (b & 1)s = s * a % mod; a = a * a % mod; b >>= 1; }return s; }
ll read() //输入外挂
{
ll res = 0, ch, flag = 0;
if ((ch = getchar()) == '-')
flag = 1;
else if (ch >= '0' && ch <= '9')
res = ch - '0';
while ((ch = getchar()) >= '0' && ch <= '9')
res = res * 10 + ch - '0';
return flag ? -res : res;
}
const ll N = 10;
struct Mat {
ll mat[N][N];
};
Mat operator *(Mat a, Mat b) {
Mat res;
me(res.mat);
for (ll i = 1; i <= 2; i++) {
for (ll j = 1; j <= 2; j++) {
for (ll k = 1; k <= 2; k++) {
res.mat[i][j] = (res.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % mod;
}
}
}
return res;
}
ll quick_pow(Mat a, ll b) {
Mat res;
me(res.mat);
for (ll i = 1; i <= N; i++) res.mat[i][i] = 1;
while (b) {
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res.mat[1][2];
}
int main() {
ll n;
cin >> n;
Mat a;
a.mat[1][1] = a.mat[1][2] = a.mat[2][1] = 1;
a.mat[2][2] = 0;
ll x = quick_pow(a, n);
ll y = quick_pow(a, n+1);
cout << (x * y) % mod << endl;
}