hdu 1568 Fibonacci 数学公式
Fibonacci
Problem Description
2007年到来了。经过2006年一年的修炼,数学神童zouyu终于把0到100000000的Fibonacci数列
(f[0]=0,f[1]=1;f[i] = f[i-1]+f[i-2](i>=2))的值全部给背了下来。
接下来,CodeStar决定要考考他,于是每问他一个数字,他就要把答案说出来,不过有的数字太长了。所以规定超过4位的只要说出前4位就可以了,可是CodeStar自己又记不住。于是他决定编写一个程序来测验zouyu说的是否正确。
(f[0]=0,f[1]=1;f[i] = f[i-1]+f[i-2](i>=2))的值全部给背了下来。
接下来,CodeStar决定要考考他,于是每问他一个数字,他就要把答案说出来,不过有的数字太长了。所以规定超过4位的只要说出前4位就可以了,可是CodeStar自己又记不住。于是他决定编写一个程序来测验zouyu说的是否正确。
Input
输入若干数字n(0 <= n <= 100000000),每个数字一行。读到文件尾。
Output
输出f[n]的前4个数字(若不足4个数字,就全部输出)。
Sample Input
0
1
2
3
4
5
35
36
37
38
39
40
Sample Output
0 1 1 2 3 5 9227 1493 2415 3908 6324 1023
思路:很明显不是递推题,那就是在线算法,给一个快速求一个即可~~
我们由递推关系F[n] = F[n-1] + F[n-2].使用数学数列的消除(数归)应该可以得到F[n]与n之间的关系式:
同时利用对10取对数的方法,即可将数值的位数化为科学计算法形式,那么在通过pow(10,小数部分)的逆向就可以得到F[n]的前几位。这时只需累乘10(即还原前几位的过程)满足范围即可;
细节:里面先计算了前40为数值。由于之后取对数化简时,我们从中括号中提了[(1+sqrt(5)/2]^n,之后变成
这时当n较大时,最后一项趋于0,所以只需计算前两项即可;
#include<iostream> #include<cstdio> #include<cstring> #include<string.h> #include<algorithm> #include<vector> #include<cmath> #include<stdlib.h> #include<time.h> #include<stack> #include<set> #include<map> #include<queue> using namespace std; #define rep0(i,l,r) for(int i = (l);i < (r);i++) #define rep1(i,l,r) for(int i = (l);i <= (r);i++) #define rep_0(i,r,l) for(int i = (r);i > (l);i--) #define rep_1(i,r,l) for(int i = (r);i >= (l);i--) #define MS0(a) memset(a,0,sizeof(a)) #define MS1(a) memset(a,-1,sizeof(a)) #define MSi(a) memset(a,0x3f,sizeof(a)) #define inf 0x3f3f3f3f #define lson l, m, rt << 1 #define rson m+1, r, rt << 1|1 typedef pair<int,int> PII; #define A first #define B second #define MK make_pair typedef __int64 ll; template<typename T> void read1(T &m) { T x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} m = x*f; } template<typename T> void read2(T &a,T &b){read1(a);read1(b);} template<typename T> void read3(T &a,T &b,T &c){read1(a);read1(b);read1(c);} template<typename T> void out(T a) { if(a>9) out(a/10); putchar(a%10+'0'); } ll F[40],n; const double dot = (sqrt(5.)+1)/2; int main() { F[0] = 0;F[1] = 1; rep1(i,2,40) F[i] = F[i-1]+F[i-2]; while(scanf("%d",&n) == 1){ if(n <= 40){ ll ans = F[n]; while(ans >= 10000) ans /= 10; out(ans); } else{ double ans = -0.5*log10(5)+1.*n*log10(dot); ans -= int(ans);//忽略了10^n,只是数值 ans = pow(10,ans); while(ans < 1000) ans *= 10; printf("%d",int(ans)); } puts(""); } return 0; }