一个简洁的斐波那契求法和它的简单应用

这个简洁的求法其实是在做题的过程中发现的,但这道题的正规做法应该不是这样,所以我就先解释一下这种考找规律的斐波那契数列求法
事实上,只要细心观察,通过简单的数学推导很容易可以得到一个式子形如F(2n)=F(N)²+F(N+1)²就是F[N]=F[N/2]²+F[(N+1)/2]²
知道了这个式子后我们很容易的可以求出当目标为奇数时的递推关系(因为奇数本身除2自动约掉+1后除2即为n/2+1)但偶数会导致(N+1)/2自动约掉
n的大小一次可以减半,如果解决了偶数形式的问题我们就可以吧这一复杂度本来为2的n次方的递归问题优化为log2n性
于是我试着列了一个方程组如下图一个简洁的斐波那契求法和它的简单应用_第1张图片
在得出
一个简洁的斐波那契求法和它的简单应用_第2张图片
可以解决这个问题

所以我们可以用log2n的递归完成对斐波那契的求解
下面我们看一下这个题的原题和题解

题目描述

Keven特别喜欢斐波那契数列,已知 fib1=1fib2​=1,对于 n>=3n>=3n>=3。fibn​=fibn−2​+fibn−1​,并且他想知道斐波那契前 n 项平方和是多少? 为了防止答案过大,请将最后的答案模 1e9+7
输入描述:
第一行一个整数 n(1<=n<=1e18)
输出描述:
在一行中输出斐波那契数列的前 n 项平方和模 1e9+7

问题就是求前n项斐波那契的平方和,可是这个题目的输入数据非常之大我们很难暴力枚举解决问题
这是我们借助一个图来作为辅助
一个简洁的斐波那契求法和它的简单应用_第3张图片

我们可以发现所有项的平方和共同组成了大矩形的面积也就是F[N]*F[N+1]我们只要求出这两项的值即可。而这时我们发现如果按照传统递归来求,时间也不够用,所以我们就用上文提到的规律来解决问题(在这里提一下,本题的正确解法应该是求矩阵快速幂)问题分解后代码就变得非常简短了(map是因为数组会越界)

#include
using namespace std;
typedef long long ll;
const ll p = 1e9 + 7;
map<ll, ll>a;
ll n;
ll f(ll n)
{
    if (a[n] != 0)
        return a[n];
    ll t = n;
    n /= 2;
    if (t % 2)
      return a[t] = f(n) * f(n) % p + f(n + 1) * f(n + 1) % p;
    else
        return a[t] = (2 * f(n - 1) % p + f(n) % p) * f(n) % p;
}
int main()
{
    cin >> n;
    a[1] = a[2] = 1;
    cout << f(n) % p * f(n + 1) % p << endl;
    return 0}

你可能感兴趣的:(c++,c)