hdu1568Fibonacci(公式变形)

->题目请戳这里<-

题目大意:中文题,略。

题目分析:要求10^9内任意菲波数的高4位,把每个菲波数求出来是不可能的,所以考虑从公式入手。

斐波那契数列公式:fn = 1/√5 [ ((1 + √5)/2)^n - ((1 - √5)/2)^n].公式并不复杂,但是如果直接代进去算的话由于n会非常大,所以会TLE,必须对公式处理一下。

因为指数n会特别大,所以要对公式降阶处理:公式两边同时以10为底取对数:

log10(fn) = log10(1/√5) + log10[((1 + √5)/2)^n - ((1 - √5)/2)^n]

= log10(1/√5) + log10[((1 + √5)/2)^n * (1 + ((1 - √5)/(1 + √5))^n]  (因为(1 - √5) / 2 是个负数,所以不能直接将上面的式子分解,处理一下)

= log10(1/√5) + n * log10[(1 + √5)/2] + log10[1 + ((1 + √5)/(1 - √5))^n]

考虑到最后一项:log10[1 + ((1 + √5)/(1 - √5))^n] = log10[1 + ((√5 - 3)/2)^n],期中(√5 - 3)/2 ≈ -0.2,再n次方后更小,所以此项趋近于0,对结果影响较小,可以忽略(为什么,想一想)。

接下来我们看答案:fn = 10^(log10(fn)),经过一处理,发现这里的指数部分还是很大,设指数部分为t,显然这个t是个浮点数,将t分成2部分:t = t0 + t1;t0代表t的整数部分,t1代表t的小数部分。fn = 10^t0 * 10 ^ t1,10^t0表示1后面跟t0个0,对fn的各位数字并无影响,而决定fn各位数数字的就是t1!所以我们只需要求出10^t1即可!这个运算量还是可以接受的,由于处理过程中我们当n比较大的时候忽略了第三项,所以当n很小的时候计算出来的结果会有误差,所以我们解决的方案是——打表!!!

详情请见代码:

#include <iostream>
#include<cmath>
#include<cstdio>

using namespace std;
int n;
double ans1;
//fibonacci公式:fn = 1/sqrt(5) * [(1 + sqrt(5))^n - (1 - sqrt(5))^n];
int fibo[21] = {0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765};
//打表输出所有的5位数以内的斐波数,至少21个,
少了会WA,因为精度会有损失!
int main()
{
    //printf("%d\n",(int)pow(10,3.123));
    //printf("%d\n",(int)pow(10,3.12));
    //printf("%d\n",(int)pow(10,3.1));
    //printf("%lf\n",pow(10,0.123));
    while(scanf("%d",&n) != EOF)
    {
        if(n < 21)
        {
            printf("%d\n",fibo[n]);
            continue;
        }
        ans1 = log10(1.0 / sqrt(5.0)) + log10((1.0 + sqrt(5.0)) / 2.0) * n;
        ans1 = ans1 - (int)ans1;
        ans1 = pow(10.0,ans1);
        //printf("%lf\n",ans1);
        while(ans1 < 1000)
            ans1 = ans1 * 10;
        int ans = (int)ans1;
        printf("%d\n",ans);
    }
    return 0;
}
//15MS	340K


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值