题目 2311: 蓝桥杯2019年第十届省赛真题-Fibonacci 数列与黄金分割

题目

Fibonacci 数列是非常著名的数列:

F[1] = 1,F[2] = 1,
对于 i > 3,F[i] = F[i − 1] + F[i − 2]

Fibonacci 数列有一个特殊的性质,前一项与后一项的比值,F[i]/F[i + 1], 会趋近于黄金分割。

为了验证这一性质,给定正整数 N,请你计算 F[N]/F[N + 1],并保留 8 位 小数。

输入
一个正整数 N。(1 ≤ N ≤ 2000000000)

输出
F[N]/F[N + 1]。答案保留 8 位小数。

样例输入

2

样例输出

0.50000000

解题思路

矩阵快速幂
快速幂常用于快速计算次数较大的乘方,比如题目 2088: 蓝桥杯算法提高VIP-快速幂。斐波那契数列最常用的方法就是矩阵快速幂,根据递推公式(矩阵具体构造过程请见矩阵构造方法)可以得到下式:
[ F ( N + 1 ) F ( N ) ] = [ F ( 2 ) F ( 1 ) ] ∗ A N + 1 − 2 \begin{aligned} [F(N+1)\quad F(N)]=[F(2)\quad F(1)]*{A}^{N+1-2} \end{aligned} [F(N+1)F(N)]=[F(2)F(1)]AN+12由此,递推公式转换成了从已知的F(1)、F(2)直接经过乘方映射到了待求的F(N+1)、F(N)。对于一般的单个整数快速幂的模板如下:

long int(int n, int a){ //a^n
	long int temp = 1;
	while (n){
		if (n&1)//二进制最后一位为1
			temp*=a;
		a*=a;
		n>>=1;//乘方次数除以2
	}
	return temp;
} 

矩阵快速幂即将返回值、变量、乘法均换成与矩阵匹配的即可。

本题思路

回到本题,开始我用的是上述方法解题,但是发现N很大时,中间变量太大了,会超出long int范围而出错。之后打算先利用矩阵快速幂+矩阵乘法打表,N∈[1,50]的结果如下:

N=1 : 1.00000000
N=2 : 0.50000000
N=3 : 0.66666667
N=4 : 0.60000000
N=5 : 0.62500000
N=6 : 0.61538462
N=7 : 0.61904762
N=8 : 0.61764706
N=9 : 0.61818182
N=10 : 0.61797753
N=11 : 0.61805556
N=12 : 0.61802575
N=13 : 0.61803714
N=14 : 0.61803279
N=15 : 0.61803445
N=16 : 0.61803381
N=17 : 0.61803406
N=18 : 0.61803396
N=19 : 0.61803400
N=20 : 0.61803399
N=21 : 0.61803399
N=22 : 0.61803399
N=23 : 0.61803399
N=24 : 0.61803399
N=25 : 0.61803399
N=26 : 0.61803399
N=27 : 0.61803399
N=28 : 0.61803399
N=29 : 0.61803399
N=30 : 0.61803399
N=31 : 0.61803399
N=32 : 0.61803399
N=33 : 0.61803399
N=34 : 0.61803399
N=35 : 0.61803399
N=36 : 0.61803399
N=37 : 0.61803399
N=38 : 0.61803399
N=39 : 0.61803399
N=40 : 0.61803399
N=41 : 0.61803399
N=42 : 0.61803399
N=43 : 0.61803399
N=44 : 0.61803399
N=45 : 0.61803399
N=46 : -1.38720213
N=47 : -2.58263042
N=48 : -0.63185946
N=49 : 2.71635390
N=50 : 0.26908094

发现当N在46时,就已经发生了中间过程的数值越界,但是这不影响我们观察到,N>=20时,输出的值应该都是0.61803399,因此根据输入的N的值分为两类:一是N∈[1,20)时,直接运算;二是N>=20时,直接输出0.61803399

当然,本题数据量较小,更好的方法是:在N∈[1,20)时直接利用函数递推式进行计算;N>=20时直接输出0.61803399

代码

#include<bits/stdc++.h>
using namespace std;
struct Node{
    int a[2][2];
};

struct Node fac;

Node multiple(Node m1, Node m2){//结果存放在b中
    int i,j,k;
    struct Node b;
    for (i=0;i<2;i++)
    {
        for (j=0;j<2;j++)
        {
            b.a[i][j] = 0;//初始化
            for (k=0;k<2;k++)
                b.a[i][j]+= m1.a[i][k]*m2.a[k][j];
        }
    }
    return b;
}

Node power(int k){
    int i,j;
    struct Node A,temp;
    for (i=0;i<2;i++)//初始化
    {
        for (j=0;j<2;j++)
        {
            A.a[i][j] = (i==j)?1:0;//单位矩阵
            temp.a[i][j] = fac.a[i][j];
        }
    }
    
    while (k!=0){
        if (k&1)//最低位为1
            A = multiple(A,temp);
        temp = multiple(temp,temp);
        k>>=1;//除以二
    }
    return A;
}

int main()
{
	int i,j,N;//(1 ≤ N ≤ 2000000000)
	int result[2],FF[i] = {1,1};//FF是已知的两个值
	scanf("%d",&N);
	struct Node f;
	fac.a[0][0] = 1,fac.a[0][1] = 1,fac.a[1][0] = 1,fac.a[1][1] = 0;//初始化
    if (N<20)
    {
        f = power(N+1-2);//第二个乘数矩阵
        for (i=0;i<2;i++)
        {
            result[i] = 0;
            for (j=0;j<2;j++)
                result[i] += FF[j]*f.a[j][i];
        }
        double r = result[1]*1.0/result[0];
        printf("%.8lf\n",r);
	}
	else
	    printf("0.61803399");
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值