斐波那契数列笔记
在中学时,我们就知道斐波那契数列是个很神奇的数列,在自然,生物,数学中都能找到他的影子,现在本人总结一下我关于斐波那契数列知识的例题。
斐波那契数列公式:
因为(1-sqrt(5))/2的绝对值小于1所以当i较大的时候,往往可以忽略掉这一项,f(n)≈((1+Sqrt(5))/2)^n/sqrt(5);
斐波那契数列性质:
1.斐波那契数列个位数数每60一循环。
2.当n大于1时,有F(n)和F(n-1)互质。
3.若i为奇数, f(i)*f(i)=f(i-1)*f(i+1)+1,否则f(i)*f(i)=f(i-1)*f(i+1)-1
4. f(n)=f(i)*f(n-i-1)+f(i+1)*f(n-i)
5.齐肯多夫定理:任何一个正整数都可以表示为若干个不连续的斐波那契数之和。
定理证明:
(证明来自百度百科)
斐波那契数列题:
1. HDU 1568:http://acm.hdu.edu.cn/showproblem.php?pid=1568
分析:题目要求斐波那契数的前4位,化简上面的公式有:f(n)=n*log10((1+sqrt(5))/2)-log10(sqrt(5));
2. HDU 1021 :http://acm.hdu.edu.cn/showproblem.php?pid=1021
分析:问第n个斐波那契数f(n)%3是否为0?算出前几个找规律:从2开始没4个一循环为yes。
3.HDU 1588 Gauss Fibonacci:http://acm.hdu.edu.cn/showproblem.php?pid=1588
分析:有g(i)=k*i+b;求F(g(i)) 其中i从0到n-1的和余上M的值,假设用S(n)来表示。那么我们首先推出S(n)的公式为:S(n)=F(g(0))+F(g(1))+F(g(2))+...+F(g(n-1))=F(b)+F(k*b)+F(2*k+b)+...+F((n-1)*k+b)。可以看出S(n)共有n项斐波那契数,一项项求斐波那契再求和是不现实的。较好的办法是把那n项斐波那契数用矩阵表示出来。对于第n项斐波那契,我们可以构造如下矩阵:
,那么对于S(n)我们就可以表示成如下矩阵形式:S(n)=Ab-1 *mat+Ak+b-1 *mat+A2*k+b-1 *mat+...+A(n-1)*k+b-1 *mat。我们令B=Ab-1 *mat,然后在提出公因式B。然后S(n)可化简为:S(n)=(I+Ak +A2*k+...+A(n-1)*k ) * B。再令D=Ak ,S(n)进一步化简为:S(n)=( I+D1 +D2 +...Dn-1 ) * B。到这里,S(n)的公式已经是最简单的了,并且也没必要再化简,因为到这里可以用二分法很快求的 D1 +D2 +...Dn-1的值。需要注意的是,k,b的值可能为0,对于这些特殊情况我们也要分情况讨论。
代码如下:
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 using namespace std; 5 __int64 MOD; 6 7 struct Matrix 8 { 9 __int64 map[2][2]; 10 int n; 11 Matrix (int k=0) 12 { 13 n = 2; 14 memset(map, 0, sizeof map); 15 if(k) for(int i=0; i<2; i++) 16 map[i][i] = 1; 17 } 18 Matrix operator * (const Matrix &a) const 19 { 20 Matrix e; 21 for(int i=0; i<n; i++) 22 for(int j=0; j<n; j++) 23 for(int k=0; k<n; k++) 24 e.map[i][j] = (e.map[i][j]+ map[i][k]*a.map[k][j]) % MOD; 25 return e; 26 } 27 Matrix operator + (const Matrix &a) const 28 { 29 Matrix e; 30 for(int i=0; i<n; i++) 31 for(int j=0; j<n; j++) 32 e.map[i][j]=(map[i][j]+a.map[i][j]) % MOD; 33 return e; 34 } 35 Matrix Pow(__int64 k) const 36 { 37 Matrix a = *this; 38 Matrix e(1); 39 while(k) 40 { 41 if(k&1) 42 e = e * a; 43 a = a * a; 44 k >>= 1; 45 } 46 return e; 47 } 48 Matrix operator * (const __int64 k) const 49 { 50 Matrix a = *this; 51 for(int i=0; i<n; i++) 52 for(int j=0; j<n; j++) 53 a.map[i][j] *= k; 54 return a; 55 } 56 Matrix GuassSum(int k) const 57 { 58 Matrix a = *this; 59 if(k==1) return a; 60 Matrix t = this->GuassSum(k/2); 61 if(k&1) 62 { 63 Matrix c = this->Pow(k/2+1); 64 t = t + c + c * t; 65 } 66 else 67 { 68 Matrix c = this->Pow(k/2); 69 t = t + t * c; 70 } 71 return t; 72 } 73 void print(char s[]="") const 74 { 75 printf("Matrix %s:\n", s); 76 for(int i=0; i<n; i++) 77 { 78 for(int j=0; j<n-1; j++) 79 printf("%I64d ",map[i][j]); 80 printf("%I64d\n",map[i][n-1]); 81 } 82 } 83 }; 84 85 int main() 86 { 87 Matrix base, mat, I(1); 88 base.map[0][0]=base.map[0][1]=base.map[1][0] = 1; 89 mat.map[0][0]=1; 90 __int64 k, b, n; 91 while(~scanf("%I64d %I64d %I64d %I64d",&k, &b, &n, &MOD)) 92 { 93 if(k==0 && b==0) 94 puts("0"); 95 else if(n==1) 96 if(b==0) 97 puts("0"); 98 else 99 { 100 Matrix B = base.Pow(b-1) * mat; 101 printf("%I64d\n", B.map[0][0]%MOD); 102 } 103 else if(b && k) 104 { 105 Matrix B = base.Pow(b-1) * mat; 106 Matrix D = base.Pow(k); 107 Matrix ans = (I + D.GuassSum(n-1)) * B;// 注意:矩阵乘法不满足交换律,次数若把B提到(I+D.GuassSum(n-1))前面会错。下同。 108 printf("%I64d\n", ans.map[0][0]%MOD); 109 } 110 else if(b==0 && k) 111 { 112 Matrix B = base.Pow(k-1) * mat; 113 Matrix D = base.Pow(k); 114 Matrix ans = (I + D.GuassSum(n-2)) * B; 115 printf("%I64d\n", ans.map[0][0]%MOD); 116 } 117 else if(b && k==0) 118 { 119 Matrix B = base.Pow(b-1) * mat; 120 B = B * n; 121 printf("%I64d\n", B.map[0][0]%MOD); 122 } 123 } 124 return 0; 125 }