hdu1568Fibonacci(公式变形)

来源:互联网 发布:算法统宗 pdf 下载 编辑:程序博客网 时间:2024/04/27 19:55

->题目请戳这里<-

题目大意:中文题,略。

题目分析:要求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;}//15MS340K


原创粉丝点击