zoukankan      html  css  js  c++  java
  • 斐波那契序列 Fibonacci

    [定理1] 标准Fibonacci序列(即第0项为0,第1项为1的序列)当N大于1时,一定有f(N)和f(N-1)互质

    其实,结合“互质”的定义,和一个很经典的算法就可以轻松证明
    对,就是辗转相除法
    互质的定义就是最大公约数为1

    数学归纳法是很有用的证明方法,我们接下来这个定理用数学归纳法就很好证明:
    [定理2]若i为奇数, f(i)*f(i)=f(i-1)*f(i+1)+1,否则f(i)*f(i)=f(i-1)*f(i+1)-1
    对,这个定理用数学归纳法可以轻松证明,大家有兴趣可以自己尝试

    [定理3] f(n)=f(i)*f(n-i-1)+f(i+1)*f(n-i)

    f(n)=f(1)*f(n-2)+ f(2)*f(n-1)
        =f(2)*f(n-3)+ f(3)*f(n-2)
        =f(3)*f(n-4)+ f(4)*f(n-3)
    看来没有错,证明方法就是这样

    这个公式也可以用来计算较大的fibonacci数除以某个数的余数

    设i=n/2 不过,为了保证计算能延续下去 需要每次保留三个值
    这样,下一次计算就可以利用这三个值来求出两个值,再相加就可以得到第三个值
    譬如,计算出f(5),f(6),f(7),可以计算出f(11)、f(12),然后推出f(13)
    就是刚才洛奇的悲鸣(364738334)所提到的矩阵方法
    我们知道我们若要简单计算f(n),有一种方法就是先保存
    a=f(0),b=f(1),然后每次设:
    a'=b b'=a+b

    并用新的a'和b'来继续这一运算

    如果大家熟悉利用“矩阵”这一工具的话,就知道,如果把a、b写成一个向量[a,b],完成上述操作相当于乘以矩阵
    0 1
    1 1
    也就是说,如果我们要求第100个fibonacci数,只需要将矩阵
    [0,1]乘上
    0 1
    1 1
    的一百次方,再取出第一项

    因为我们知道,矩阵运算满足结合律,一次次右乘那个矩阵完全可以用乘上那个矩阵的N次方代替,更进一步,那个矩阵的N次方就是这样的形式:
    f(n-1) f(n)
    f(n) f(n+1)

    而求矩阵的N次方,由于矩阵乘法满足结合律,所以我们可以用log(N)的算法求出——这个算法大家都会么?
    一个是二分,一个是基于二进制的求幂

    二分的原理:要求矩阵的N次方A(N),设i=N/2若N%2==1, 则 A(N)=A(i)*A(i)*A(1)若N%2==0, 则 A(N)=A(i)*A(i)

    基于二进制的原理:将N拆为二进制数,譬如13=1101那么 A^13= A^8 * A^4 * A^1 (这里^表示幂运算)

    也就是说,由A^1开始,自乘得到A^2,然后自乘得到A^4,如果N对应位为1,则将这个结果乘到目标上去

    这样的话,将所有乘法改为模乘,就可以得到一个较大Fibonacci数除以M的余数

    若不用递归,其实类似

    http://acm.pku.edu.cn/JudgeOnline/problem?id=3070
    这里用的fib矩阵略有不同,是
    f(n+1) f(n)
    f(n) f(n-1)
    但实际上可以验证效果是一样的

    这题是要求求F(n)的最后四位数,所有乘法过程增加一个模10000的步骤即可,大家可以收藏稍候AC

    关于矩阵我们告一段落,等下会回来继续探讨利用矩阵来解决复杂些的Fibonacci问题

    http://acm.hdu.edu.cn/showproblem.php?pid=1568
    我们来看这题,这题要求求出Fibonacci某项的前四位

    当然,用矩阵也可以解决这道题——只要将乘法改为乘并保留前四位

    我们采用double 保留整数部分四位 这题最好还是double吧

    不过显然有更好的解法——如果我们知道Fibonacci序列的通项公式

    F(n) = (((1+Sqrt(5))/2)^n - ((1-Sqrt(5))/2)^n)*1/Sqrt(5)

    不过组合数学里也有这一公式的推导方法 叫做“线性齐次递推式”

    这个解法的核心是,通解是某个数的幂 将f(n)=x^n代入递推方程,可以解出三个通解 0和 (1+sqrt(5))/2

    通常把“0”称作平凡解,那么特解就是通解的某个线性组合

    再代入f(0)=0 f(1)=1,就可以得出我们刚才的公式

    不过通常情况下,我们只需要记住那个公式就可以了

    提醒大家,记忆公式的时候千万别忘记了系数1/sqrt(5)

    因为(1-sqrt(5))/2的绝对值小于1

    所以当i较大的时候,往往可以忽略掉这一项
    f(i)≈((1+Sqrt(5))/2)^n/sqrt(5);

    所以,刚才列举出的HDOJ的1568,可以很简单的30以内直接求解,30以上采用这个公式,还是用log(N)求幂的算法求解
    恩,就是公式的前半部分

    http://acm.hdu.edu.cn/showproblem.php?pid=1021
    http://acm.zju.edu.cn/show_problem.php?pid=2060
    Fibonacci某项是否被3整除

    [定理5] 标准Fibonacci序列对任意大于2的正整数的余数序列,必然是以“0 1”为循环节开头的序列

    显然0、1是序列开头,也就是说序列开头就是循环节开头

    循环长度的计算貌似是个比较难的问题,我一时还没有想到有效解法,不过,要说明的是,计算复杂度时,这个循环节长度应该按复杂度O(N^2)计算

    恩,证明方法是利用同余定理、反证法,还有我们之前证明过的相邻项一定互质的定理,留给大家家庭作业

    http://acm.hdu.edu.cn/showproblem.php?pid=1588
    这是前天比赛关于Fibonacci的一道题,大家先看看题。
    Description看后半部分就行了

    现在告诉大家一种正确解法,然后大家就可以去搞定这道题向别人炫耀了

    首先,我们将问题整理一下,就是对等差数列 ai=k*i+b,求所有的f(ai)之和除以M的余数

    当0<=i<N

    大家有没有想到,因为ai是等差数列,倘若f(ai)也是个等什么序列,那说不定就有公式求了

    f(ai)显然不是等差数列,直接看上去也不是等比数列

    但是如果把f(ai)换成我们刚才所说的Fibonacci矩阵呢?

    是的,可是我们对矩阵是直接求幂即可,由于矩阵加法的性质,我们要求A^ai的右上角元素之和,只要求A^ai之和的右上角元素

    就矩阵这个东西来说,完全可以看作一个等比数列,
    首项是:A^b
    公比是:A^k
    项数是:N

    呵呵,我们可以把问题进一步简化

    因为矩阵的加法对乘法也符合分配律,我们提出一个A^b来,形成这样的式子:
    A^b*( I + A^k + (A^k)^2 + .... + (A^k)^(N-1) )

    A^b 和 A^k 显然都可以用我们之前说过的方法计算出来,这剩下一部分累加怎么解决呢

    简单起见,设A^k=B
    要求 G(N)=I + ... + B^(N-1),设i=N/2
    若N为偶数,G(N)=G(i)+G(i)*B^i
    若N为奇数,G(N)=I+ G(i)*B + G(i) * (B^(i+1))

    呵呵,这个方法就是比赛当时ACRush用的
    而农夫用的则是更精妙的方法,大家可想知道

    我们来设置这样一个矩阵
    B I
    O I
    其中O是零矩阵,I是单位矩阵

    将它乘方,得到
    B^2 I+B
    O   I
    乘三方,得到
    B^3 I+B+B^2
    O   I
    乘四方,得到
    B^4 I+B+B^2+B^3
    O   I

    既然已经转换成矩阵的幂了,继续用我们的二分或者二进制法,直接求出幂就可以了

    http://online-judge.uva.es/p/v110/11089.html
    大家来读读这一题

    Fibinary数是指没有相邻的两个1的二进制数。给N,求出第N大的Fibinary数

    相对于二进制中每一位的值是2的幂,十进制中每一位的值是十的幂,
    Fibonacci进制是每一位的值是对应Fibonacci数的一种计数系统。
         8 5 3 2 1
    1     1
    2     1 0
    3     1 0 0
    4     1 0 1
    5     1 0 0 0
    6     1 0 0 1
    7     1 0 1 0
    8     1 0 0 0 0
    9     1 0 0 0 1
    10   1 0 0 1 0
    11   1 0 1 0 0
    12   1 0 1 0 1
    以上是前12个数字对应的十进制到Fibonacci进制的表格

    Fibonacci的运算方法很奇怪。首先,它每一位上非0即1,而且不同于二进制的逢二进一或者十进制的逢十进一,它的进位方法是逢连续两个1,则进1

    譬如
    1010110==> 1011000 ==> 1100000==>10000000

    在最低位有个特殊情况,最低位既可以逢2进1,也可以和次低位一起逢相邻进1
    这种奇怪的进位方法,换句话描述就是,不存在两个连续的1
    因为Fibonacci数其实也增长很快,int范围内好像只有46个,本题只需要用最简单的办法转换成Fibonacii进制即可
    其中一题是
    http://www.mydrs.org/program/down/ahoi2004day1.pdf
    中的第二题,叫做数字迷阵
    还有一题是PKU上的很出名的取石子问题
    http://acm.pku.edu.cn/JudgeOnline/problem?id=1067

    这题相当复杂,大家可以自己思考,往Fibonacci上想,也可以阅读这里的论文:
    http://episte.math.ntu.edu.tw/articles/mm/mm_03_2_02/index.html
    http://acm.pku.edu.cn/JudgeOnline/problem?id=2967

    另外这题 可以利用Fibonacci判断数据范围进行优化设计。不过貌似可以水过去,仅仅给大家提供个思路罢

    关于Fibonacci和黄金分割,还有很多更高明的结论和定理,希望大家也继续讨论,将自己的知识和他人共享
    http://episte.math.ntu.edu.tw/articles/mm/mm_02_4_10/index.html
    中例3详细讲述了用生成函数来计算Fibonacci数公式的运算过程。http://acm.hdu.edu.cn/showproblem.php?pid=1568
    Fibonacci 求fibonacci前4位

    http://acm.hdu.edu.cn/showproblem.php?pid=1588
    Gauss Fibonacci
    http://acm.pku.edu.cn/JudgeOnline/problem?id=1067
    取石子问题
    http://episte.math.ntu.edu.tw/articles/mm/mm_03_2_02/index.html 是报告
    http://acm.pku.edu.cn/JudgeOnline/problem?id=3070
    Fibonacci矩阵
    http://acm.hdu.edu.cn/showproblem.php?pid=1021

    http://acm.zju.edu.cn/show_problem.php?pid=2060
    Fibonacci某项是否被3整除
    http://acm.pku.edu.cn/JudgeOnline/problem?id=2116
    Fibonacci进制计算
    http://acm.pku.edu.cn/JudgeOnline/problem?id=2967
    利用Fibonacci判断数据范围进行优化设计。
    http://online-judge.uva.es/p/v110/11089.html
    Fi-binary numbers,Fibonacci进制。
    http://www.mydrs.org/program/down/ahoi2004day1.pdf
    第二题 数字迷阵   这些,是今天涉及到的资料和网页

    转至:http://www.cnblogs.com/Knuth/archive/2009/09/04/1559951.html

    下面是一些题目的解题报告了,后面如果发现新的会补上来(不知道 FH算不算:-))
    1. pku3070 Fibonacci
    http://acm.pku.edu.cn/JudgeOnline/problem?id=3070
    这个题目按照题意做就可以轻松的搞定了.问题关键是给出了我们另外一种求解Fibonacci的方法。利用矩阵乘法!
    那为什么它就比递推式和通项公式要好呢,原因是因为Fibonacci的增长速度非常快,通常普通解法没有办法求得
    后面的大数,所以题目通常要求取模,而如果用通项,肯定不够精确了,用递推公式又肯定会超时(比如要你求第1000000000个
    Fibonacci数模10000000的最终结果),这个时候转换为求矩阵的幂次,可以在logn的时间内搞定.
    我比较喜欢下面这个形式
    |0 1|    |f(0)|                   |f(1)|
                             ===>  
    |1 1|    |f(1)|                   |f(0)+f(1)| 后面这个也就是f(2)了
    如果令 A为那个0,1矩阵,可以发现
    f(n) = (A^n).a12 * f(1) (a12为右上角的元素值)
    特别的 ,
    A^0 = I (I是单位矩阵)

    2. hdu1021 Fibonacci Again
    http://acm.hdu.edu.cn/showproblem.php?pid=1021
    通过一个模3障眼法,其实也可以使用上述的矩阵幂次进行求解.不过看题目的数据量,貌似直接用推倒也可以搞定

    3. hdu1568
    http://acm.hdu.edu.cn/showproblem.php?pid=1568
    输出一个fibonacci的前4个字母
    这个要使用fibonacci的通项公式了
    ((1+√5)/2 )^n - ((1-√5)/2)^ n
    --------------------------------
                 √5
    可以发现后面的((1-√5)/2)^ n 当n很大的时候数值非常小,可以忽略,不会对前4位造成影响。
    因此转变为了
    ((1+√5)/2 )^n
    ------------------
        √5
    这个式子随着n的增长也是增长很快,但是我们可以发现,题目要求的是前4位,因此我们发现将长度固定在某个范围
    之内(即如果数大了,就除一下),这样的话就可以取到前4位了.

    4. hdu1250 Hat's Fibonacci
    http://acm.hdu.edu.cn/showproblem.php?pid=1250
    我用的赤裸裸的高精度算的把结果存起来了,大汗.内存占了18M. Statistic里面的貌似都很少的样子.
    后来我用数组去循环递推做的,内存自然就下降下来了.这个题目貌似也可以构造矩阵,只不过要在计算
    里面处理好高精度.

    5. hit1214 Fibonacci Coding
    http://acm.hit.edu.cn/ojs/show.php?Proid=1214&Contestid=0
    题目大意是去除相邻的1,改变成前面一个.
    我是直接模拟的,从高位开始判断,如果相邻位为1且前面一个为0,则变化,直至没有出现该情况为止
    要注意的是,如果使用string,且在高位前产生进位的时候,要更新len,如果你没有直接调用size的话.

    6. hit1533 Fibonacci Numbers
    http://acm.hit.edu.cn/ojs/show.php?Proid=1533&Contestid=0
    高精度,与hdu1350类似

    7. hit1864 Fibonacci
    http://acm.hit.edu.cn/ojs/show.php?Proid=1864&Contestid=0
    这个是求第k个finbonacci数的位数,求位数,用大数就太不明智了.
    这里我同样的使用了通项的, 当n比较大的时候,利用变化过的通项
    ((1+√5)/2 )^n
    ---------------
        √5
    那么求位数就用 log10(F) + 1
    再利用log10(a*b) = log10(a) + log10(b), log10(a/b) = log10(a) - log10(b)

    8. hit2060 Fibonacci Problem Again
    http://acm.hit.edu.cn/ojs/show.php?Proid=2060&Contestid=0
    大意求第a个到第b个之间所有fibonacci的数和。
    这个有点小技巧在里面,可以自己推导一下:
    F(3) = F(1) + F(2)
    F(4) = F(2) + F(3) = 1 * F(1) + 2 * F(2)
    F(5) = F(3) + F(4) = 2 * F(1) + 3 * F(2)
    F(6) = F(4) + F(5) = 3 * F(1) + 5 * F(2)
    F(7) = F(5) + F(6) = 5 * F(1) + 8 * F(2)
    F(8) = F(6) + F(7) = 8 * F(1) + 13 * F(2)

    S(3) = 2 * F(1) + 2 * F(2)
    S(4) = 3 * F(1) + 4 * F(2)
    S(5) = 5 * F(1) + 7 * F(2)
    S(6) = 8 * F(1) + 12 *F(2)
    S(7) = 13 *F(1) + 20 *F(2)
    不难发现,
    S(n) = F(n + 2) - F(2)
    因此题目就转换为了求 F(b + 2) - F(a + 2 - 1)
    而又是大数取模,考虑使用矩阵求幂

    9. hit2065 Fibonacci Number
    http://acm.hit.edu.cn/ojs/show.php?Proid=2065&Contestid=0
    赤裸裸的Fibonacci,最基本的那种

    10. hit2204 Fibonacci Numbers
    http://acm.hit.edu.cn/ojs/show.php?Proid=2204&Contestid=0
    这个题目相当于求第k个Fibonacci的前4位和后4位,那么前面的题目
    综合起来,就是前4位用通项,后4位用矩阵求模。
    就不难了。要注意的是,前面求前4位的时候我用的O(n)的做法,过了。
    这边如果仍然采用O(n)的会TLE,必须采用O(logn),求幂次的方法才能过.

    11. hit2255 Not Fibonacci
    http://acm.hit.edu.cn/ojs/show.php?Proid=2255&Contestid=0
    这个题目是个BT题,交了我n次,后来发现是s=0的时候负数情况没有处理,汗.
    粗看一下,这个题目和hit2060一样,不过这里好像都泛化了。这里面的规律
    可没有上面那题那么好找了。wy他们貌似直接推导S的公式,都是采用的什么
    等比数列弄的,我和felica讨论了一下,发现了一个好的解法。通过构造分块
    矩阵,可以很好的解决这个问题。
    首先构造
    |0 1| |f(0)|
    |q p| |f(1)|
    这个可以利用矩阵幂次求得任何一个F(n),可惜这里是求和,
    那么令A=前面那个p,q的矩阵
    则S(n) = f(0) + f(1) + ... + f(n) = f(0) + (A + A^2 + ... + A^n)*F所得矩阵的右上角的值
    那么如何求得A + A^2 + ... + A^n呢
    可以继续构造如下的分块矩阵,其中I是单位矩阵
    |A I|
    |0 I|
    令R等于上面的矩阵,则
    R^2 = |A^2   A*I + I|
          |0     I      |
    R^3 = |A^3   A^2 * I + A * I + I|
          | 0     I                 |
    可以发现右上角即为I + A + A^2 + ... + A^n,多个I后面给减掉就可以了
    这样我们同样可以再次利用矩阵幂次求得R^n
    则S(n) = ((R^(n+1).m12 - I) * F).a12 + f(0)
    可以很完美的解决这个问题.

    12. hnu10072 Fibonacci Number
    http://acm.hnu.cn:8080/online/?action=problem&type=show&id=10072&courseid=0
    与hit2065一样

    13. tju1208 Fibonacci Numbers
    http://acm.tju.edu.cn/toj/showp1208.html
    与hit1533一样

    14. zju2060 Fibonacci Again
    http://acm.zju.edu.cn/show_problem.php?pid=2060
    与hdu1021一样

    15. zju1828 Fibonacci Numbers
    http://acm.zju.edu.cn/show_problem.php?pid=1828
    与hit1533一样

    16. zju2672 Fibonacci Subsequence
    http://acm.zju.edu.cn/show_problem.php?pid=2672

    又是一道bt题,时间卡的非常之紧.
    这个题目我使用的dp+hash.
    记d(i,j)为以第i个数作为结尾,前一个数是第j个的fibonacci串的最大长度
    则 d(i,j) = max{d(j, i - j)} + 1,
    注意查找data[i] - data[j]的时候利用hash查找到的应该是j小的所有当中最大下标的那个。
    因此需要在每次循环结束的时候更新已存在的数的hash。


    17. hzu1060 Fibonacci数列
    http://acm.fzu.edu.cn/problem.php?pid=1060
    与hit1533相同

    18. fjnu1158 Fibonacci数列
    http://acm.fjnu.edu.cn/show?problem_id=1158
    与hit1533相同

    19. zjut Fibonacci数
    http://acm.zjut.edu.cn/ShowProblem.aspx?ShowID=1029
    与hit2065一样,题目描述稍有不一样


    总结一下,主要能够考察的是
    1. 求解Fibonacci的某一项(这个范围一般在45之内)
    2. 求解Fibonacci的某一项模K(这个一般是大数),通用解决方法是构造矩阵求幂次
    3. 求解Fibonacci的前多少位 (这个一般是大数), 通用解法是使用通项公式
    4. 求解Fibonacci的后多少位,这个和取模类似
    5. 求解Fibonacci的前n项和,利用推导式, S(n) = F(n + 2) - F(2)即可
    6. 更多的是基于Fibonacci的综合题,包括DP,构造,等等.

    =======================================================
    另外,gardon补充了一题:
    就普通的f(0)=0,f(1)=1,f(n)=f(n-1)+f(n-2)
    给数列an=k*n+b
    保证k>0,b>=0
    求1到n的f(an)之和
    输入k、b、m,求出那个和模m的值
    b, m, n数的范围都是10^9以内
    k <=20
    这个题目仍然可以使用hit那个BT题的做法。先构造矩阵
    应该是
    0 1
    1 1的幂次了(主要是使得F'(n + 1) = F'(n)*矩阵),然后构造求和矩阵就可以了.

    矩阵的方法。

    思想来源上上次PKU的acm warmup
    http://acm.pku.edu.cn/JudgeOnline/problem?id=3070

    {{F(n+1),F(n)},
    {F(n),F(n-1)}}

    =

    {{1,1}      ^n
    {1,0}}

    我当时就想,用加法算都只能是O(n)的,换成n个矩阵的连乘不是更废劲吗?其实不然,乘法方法有比加法更好的性质,用加法只能利用前两个的值,而乘法却不同,因为乘法有结合律,可以大幅度下降算法的耗时。

    令A(n)表示一个矩阵序列

    A(n)=

    {{F(n),F(n-1)},
    {F(n-1),F(n-2)}

    那么A(2)={{1,1},{1,0}},由那个表达式得到:

    A(n)=A(2)^(n-1),A(2)是己知的2*2矩阵,现在的问题就是如何求

    A(2)^n

    因为方阵的乘法有结合律,所以

    A(2)^n=A(2)^(n/2)*A(2)^(n/2),不妨设n是偶数

    所以求A(n)就可以化成求A(n/2)并作一次乘法,所以递归方程是:

    T(n)=T(n/2)+O(1)

    它的解是O(lbn),不可思议吧。

    最后我们要观察这样的矩阵方法可否推广到一般情形,我们暂且称这样的递推序列为‘c阶线性递推方程’吧,它的意思就是说F(n)由与n相距c远的前面的一些F(m)组成的线性组合,比如Fibonacci数列的最大距离就是2,所以这样的递推式需要确定一个序列至少要知道最初的c个己知初值,我们的目的就是要求这样的递归式的一般算法:

    F(n)={F(n-1),F(n-2),...F(n-c)}*K
    {F(1),F(2),,,F(c)}^T=C

    其中K={x1,x2,...xc}^T,C={c1,c2,...cc}^T都是非0的常向量。

    我们构造A(n)表示一个c*c的矩阵序列,且形式为

    A(n)=

    {{F(n),F(n-1),F(n-2),...F(n-c+1)},
    {F(n-1),F(n-2),F(n-3),...F(n-c)},
    ......
    {F(n-c+1),F(n-c),F(n-c-c),...F(n-2c+2)}}

    为了使它有意义,n-2c+2>=1,所以n>=2c-1,所以A(n)的初始矩阵是A(2c-1),可以按递归式直接构造它,然后我们考虑A(n)的生成矩阵会是什么样子,设为G,于是应满足:

    A(n)=A(n-1)G

    观察A(n-1)的第一行,它刚好就是{F(n-1),F(n-2),...F(n-c)},由递推式,知G的第一列应为K,而第二列设为x,则要满足{F(n-1),F(n-2),...F(n-c)}x=F(n-1),很简单,x={1,0,0,...},同样第三列是{0,1,0,0,...},所以右边应该是一个(c-1)*(c-1)的单位矩阵I再在最下面补上一行0,于是G可以表示为:

    G={K,{I,0}^T}

    于是A(n)的通项就是

    A(n)=A(2c-1)*G^(n-2c+1)

    比如Fibonacci数列的K={1,1}^T,所以
    G={K,{I,0}^T}=
    {{1,1},
    {1,0}}

    再举一个例子,也是以前做过的一个题,母牛生小牛的题,在一个农场上有很多母牛,第1年有一只母牛,而且每过4年,母牛会开始生小母牛,小母牛过4年后也会开始生,此后就每年生一只小母年,问第n年时有多少只母牛?

    简单例出前几个数字:1,1,1,2,3,4,6,。。。会发现一个规律,就是第n年的母牛数F(n)恰等于前一年的母牛数F(n-1),以及前三年的母牛数F(n-3)之和,其实直接得到这个递推式也不难,因为F(n-3)到F(n)刚好4年(第4年),所以F(n-3)都是一些可以生仔的牛数,它们会添加F(n-3)个小牛,同时F(n-1)是所有的牛妈妈,那当然有F(n)=F(n-1)+F(n-3)。

    它的K={1,0,1},c=3,生成矩阵G=
    {{1,1,0},
    {0,0,1},
    {1,0,0}}

    所以有A(n)=A(3)*G^(n-2)

    A(3)=
    {{1,1,1},
    {1,1,0},
    {1,0,0}}

    从O(2^n)到O(n),再到O(lbn),效率提高得也太猛烈了,不过一点要提出来,不管什么样的算法,Fiboacci数列本身数值的递增是指数型的,所以要想算很高阶的结果,也近乎不太可能,所以经常会在一个模数范围内考虑。

    F(2*n)=sigma(C(n,k)F(k)) k>=0,k<=n

     timus ural 1133. Fibonacci Sequence

    http://acm.timus.ru/problem.aspx?space=1&num=1133 

    import java.io.BufferedInputStream;
    import java.math.BigInteger;
    import java.util.Scanner;

    public class Main {

    public static void main(String[] args) {
    Scanner cin = new Scanner(new BufferedInputStream(System.in));
    int nmax = 2002, i, ii, jj, kk, temp;
    BigInteger ni, nii, nj, tempn;
    BigInteger[] fib0 = new BigInteger[nmax];
    BigInteger[] fib1 = new BigInteger[nmax];
    fib0[0] = BigInteger.ONE;
    fib0[1] = BigInteger.ZERO;
    fib1[0] = BigInteger.ZERO;
    fib1[1] = BigInteger.ONE;
    for (i = 2; i < nmax; i++) {
    fib0[i] = fib0[i - 1].add(fib0[i - 2]);
    fib1[i] = fib1[i - 1].add(fib1[i - 2]);
    }
    while (cin.hasNext()) {
    ii = cin.nextInt();
    ni = cin.nextBigInteger();
    jj = cin.nextInt();
    nj = cin.nextBigInteger();
    kk = cin.nextInt();
    ii += 1000;
    jj += 1000;
    kk += 1000;
    if (ii > jj) {
    temp = ii;
    ii = jj;
    jj = temp;
    tempn = ni;
    ni = nj;
    nj = tempn;
    }
    if (ii == jj - 1) {
    nii = nj;
    } else {
    nii = nj.subtract(ni.multiply(fib0[jj - ii])).divide(
    fib1[jj - ii]);
    }
    if (kk == ii) {
    System.out.println(ni);
    } else if (kk == ii + 1) {
    System.out.println(nii);
    } else {
    if (kk > ii) {
    ii++;
    while (ii < kk) {
    tempn = ni.add(nii);
    ii++;
    if (ii == kk) {
    System.out.println(tempn);
    break;
    }
    ni = nii;
    nii = tempn;
    }
    } else {
    while (ii > kk) {
    tempn = nii.subtract(ni);
    ii--;
    if (ii == kk) {
    System.out.println(tempn);
    break;
    }
    nii = ni;
    ni = tempn;
    }
    }
    }
    }
    }
    }

  • 相关阅读:
    【读书笔记】iOS-UDID
    【读书笔记】iOS-优化内存
    【读书笔记】iOS-处理内存警告
    【读书笔记】iOS-方法声明
    【读书笔记】iOS-属性
    【读书笔记】iOS-强类型与弱类型
    【读书笔记】iOS-Objective-C编程
    【读书笔记】iOS-Interface Builder
    【读书笔记】iOS-开发者证书
    【读书笔记】iOS-成为一名开发者
  • 原文地址:https://www.cnblogs.com/xiaoxian1369/p/2155028.html
Copyright © 2011-2022 走看看