1. 程式人生 > >hdu 1568 求斐波數的前四位

hdu 1568 求斐波數的前四位

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個數字,就全部輸出)。

  剛開始看到這麼大的資料,於智商有限的我,表示無能為力,於是YY數論的東西,最後以無結果告終- -!

  後搜到AC的部落格中一篇此題的詳細剖析過程,頓時對核武的膜拜又升了一個檔次.......

  要點:

    1. log取對數的運用

    2. Fib數的通項公式

先看對數的性質,loga(b^c)=c*loga(b),loga(b*c)=loga(b)+loga(c);
假設給出一個數10234432,那麼log10(10234432)=log10(1.0234432*10^7)=log10(1.0234432)+7;

log10(1.0234432)就是log10(10234432)的小數部分.

log10(1.0234432)=0.010063744
10^0.010063744=1.023443198
那麼要取幾位就很明顯了吧~
先取對數(對10取),然後得到結果的小數部分bit,pow(10.0,bit)以後如果答案還是<1000那麼就一直乘10。
注意偶先處理了0~20項是為了方便處理~

這題要利用到數列的公式:an=(1/√5) * [((1+√5)/2)^n-((1-√5)/2)^n](n=1,2,3.....)


取完對數


log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0)+log10(1-((1-√5)/(1+√5))^n)其中f=(sqrt(5.0)+1.0)/2.0;
log10(1-((1-√5)/(1+√5))^n)->0
所以可以寫成
log10(an)=-0.5*log10(5.0)+((double)n)*log(f)/log(10.0);
最後取其小數部分。

#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int main() {
	int f[22];
	f[0] = 0;
	f[1] = 1;
	f[2] = 1;
	int i;
	for(i = 3 ; i <= 20 ; i ++) 
	f[i] = f[i-1] + f[i-2];
	int n;
	while(~scanf("%d",&n)) {
		if(n < 21) {
			printf("%d\n",f[n]);
			continue;	
		}	
		double e , k;
		k = -0.5*log10(5) + n*1.0*log10((1+sqrt(5))/2.0)+log10(1-pow((1-sqrt(5))/(1+sqrt(5)),n));
		k = k - floor(k);
		e = pow(10.0,k);
		while(e < 1000) {
			e = e*10;	
		}
		printf("%d\n",(int)e);
	}
}