W3 school 菜鸟教程 我要自学网 信息学奥赛NOI 花哥的博客 不逼自己一把,怎知自己有多优秀——校长语录

一个差生解1642Fibonacci 第 n 项

 

1642: 【例 2】Fibonacci 第 n 项

时间限制: 1000 ms         内存限制: 524288 KB
提交数: 70     通过数: 22 
【题目描述】
大家都知道 Fibonacci 数列吧,f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2f1=1,f2=1,f3=2,f4=3,…,fn=fn−1+fn−2 。

现在问题很简单,输入 nn 和 mm,求 fnmodmfnmodm。

【输入】
输入 n,mn,m。

【输出】
输出 fnmodmfnmodm。

【输入样例】
5 1000
【输出样例】
5
【提示】
数据范围与提示:

对于 100% 的数据, 1≤n≤2×109,1≤m≤109+101≤n≤2×109,1≤m≤109+10
1642: 【例 2】Fibonacci 第 n 项

 由于之前也做过几次Fibonacci数列问题,随手翻了下,看到了一本通网站1642:Fibonacci数列第n项。起初并没有注意这个题是在哪个章节,但看了一下题目,感觉不太难,然后就开始做了。上手后,再细看条件,“对于 100% 的数据, 1n2×10^9,1m10^9+10”,这很是要命啊,估计能做到O(n)的时间复杂度都怕是没戏。于是,得思考更高级的时间复杂度算法,初步想到的是O(logn),二分法就是最常见的O(logn)时间复杂度了。那我的想法就集中在f(n)与f(n/2)的关系上了。由于这个题边界条件是两个,f(1)=f(2)=1,估计要直接用f(n/2)表示f(n)是有难度的,还有n可能是一个奇数,也可能是偶数,所以我思考的方向是用两项表示两项:比如用f(3)、f(4)表示f(7)、f(8),再用f(7)、f(8)表示f(15)、f(16)等。为了方便验算,我先求了前面的部分项:f(3)=2,f(4)=3,f(5)=5,f(6)=8,f(7)=13,f(8)=21,f(9)=34,f(10)=55。f(3)=f(2)+f(1),f(4)=f(3)+f(2)=2f(2)+f(1),到这看不出什么特殊性,继续...,f(5)=f(4)+f(3)=2f(3)+f(2), f(6)=f(5)+f(4)=3f(3)+2f(2),有点眉目了,还不明显,再算:f(7)=3f(4)+2f(3),f(8)=3f(5)+2f(4),f(9)=3f(6)+2f(5),f(10)=3f(7)+2f(6),似乎看到f(n+3)=3f(n)+2f(n-1),但不是我们的目标,继续向下:f(8)=5f(4)+3f(3),f(9)=5f(5)+3f(4),f(10)=5f(6)+3f(5)=8f(5)+5f(4),这时可以看到“系数似乎也是数列是的项”,如果是这样,那f(7)=f(4)*f(4)+f(3)*f(3), f(9)=f(4)*f(4)+f(5)*f(5),再验证,没错。偶数呢?f(8)=f(5)*f(4)+f(3)*f(4)=(f(4)+f(3))*f(4)+f(4)*f(3)=f(4)*f(4)+2*f(4)*f(3),f(10)=f(5)*f(5)*2*f(5)*f(4),由此推广可知: f(2n+1)=f(n+1)*f(n+1)+f(n)*f(n),f(2n)=f(n)*f(n)+2*f(n)*f(n-1),二分法基本实现,至于证明,我就不做了,直接上网站提交就知道对大数是否成立了。

    不过,还有一个问题,最初我是直接用递归写的程序,但发现会超时,我做了一个跟踪,发现n到1w的时候运算次数就400W次了,所以不能用,于是我想到了记忆递归,直接开个大数组,n的取值是2X10^9,我开了数组a[2e9],编译就报错,开太大了,只好调到a[2e7],部分记忆,还好,能过。

#include<iostream>
using namespace std;
long long const mxn=20000011;
long long n,m,a[mxn];
long long fb(long long n)
{
    if(n==1||n==2)return 1;
    if(n>=mxn){
        long long t1=fb(n/2)%m,t2;
        if(n%2)t2=fb(n/2+1)%m,t1=(t1*t1+t2*t2)%m;
        else t2=fb(n/2-1),t1=(t1*t1+2*t1*t2)%m;
        return t1;
    }
    else
    {
        if(a[n]==0)
        {
            long long t1=fb(n/2)%m,t2;
            if(n%2)t2=fb(n/2+1)%m,a[n]=(t1*t1+t2*t2)%m;
            else t2=fb(n/2-1),a[n]=(t1*t1+2*t1*t2)%m;
        }
        return a[n];
    }
}
int main()
{
    cin>>n>>m;
    cout<<fb(n);
    return 0;
 } 
1642源代码

 提交到网站,嘿嘿,过了!

 

如有不妥,请指教。

后来才看了这一部分属于矩阵,然后拿书出来看了原书解答,真心不懂,需要花点时间去啃这块硬骨头了。

 

posted @ 2019-03-17 19:18  耍人  阅读(408)  评论(0编辑  收藏  举报