hdu1568 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說的是否正確。
 
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
 
以前從來都沒有見過這種題,於是上網查了一些資料,感覺還是比較好理解的,用到了很多意想不到的東西
首先是Fabonacci數列的通項公式:

之後又運用了以10爲底的對數函數的性質,我們先對上面這個等式的兩邊取對數(以10爲底),得到:

根據經驗可以知道,當n小於21的時候,斐波那契數列的值是小於4位數的,所以我們只討論n大於21的情況。當n大於21的時候這項是趨近於0的,所以我們暫時不管它,所以可以粗略得到這樣的等式:


我們令等號右邊的式子爲k,則我們得到等式:


所以10^k = F(n),而以10爲底的對數函數有一個很有意思的性質,舉個例子來說:10^1.5 =31.62277,而當我們取k = 1.5的小數部分時,我們發現:10^0.5 = 3.162277 ;其餘的例子隨便舉,不論是:10^2.3和10^0.3還是10^1.3和10^0.3什麼的,結果都只是小數點的位置在變化。反過來,假設給出一個很大的數12345678,那麼log10(12345678) = log10(1.2345678*10^7) = log10(1.2345678) + 7,結果呢,log10(1.2345678)就是log10(12345678)的小數部分。

代碼:
#include<iostream>
#include<cmath>
using namespace std;
int Fibo[30];
void getFibo(int n)
{
    Fibo[0] = 0;
    Fibo[1] = 1;
    for(int i=2;i<n;i++)
    {
        Fibo[i] = Fibo[i-1] + Fibo[i-2];
    }
}

int main()
{
    int n;
    getFibo(21);
    while(cin>>n)
    {
        if(n<21)
        {
            cout<<Fibo[n]<<endl;
        }
        else
        {
            double a = (1+sqrt(5))/2;
            double temp = -0.5*log10(5.0) + n*log10(a);
            temp -= (int)temp;
            temp = pow(10.0,temp);
            while(temp<1000)
            {
                temp *= 10;
            }
            cout<<static_cast<int>(temp)<<endl;
        }
    }
    return 0;
}

爲什麼我麼要捨去(1-sqrt(5))/2的部分?
我個人認爲原因有兩個,原因之一:當n越來越大的時候,這個數會趨近於0,不會影響運算結果;原因之二:減少運算量,我一開始沒有把這項捨去,結果提交的時候越界了。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章