代码改变世界

有关Fibonacci题目的小结

2007-01-16 22:53  老博客哈  阅读(3920)  评论(11编辑  收藏  举报

有关Fibonacci题目的小结 
                                                                                                      by drizzlecrj@seu

虽然临近期末考试,做题的欲望却丝毫没有减退。算了,这三天堕落了一下,把一些OJ上含有Fibon字样的题目给割掉了。
下面就要正式的进入复习阶段了,等考试完再回来。
下面是一些题目的解题报告了,后面如果发现新的会补上来(不知道 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)*矩阵),然后构造求和矩阵就可以了.

Answer