->题目请戳这里<-
题目大意:中文题,略。
题目分析:要求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