【斐波拉契数列】悟空学艺(Monkey.pas/c/cpp)

悟空学艺
monkey.pas/c/cpp

Description
话说当初大闹天宫的猴头反斗精——孙悟空来到了21世纪。当他通过时空隧道来到21世纪时才发现世界发生了翻天覆地的变化。于是他决定来中国的泰山学艺。他在海南腾云驾雾来到泰山脚下,谁知脚下却有两个人把守。他走上前对他们说:“喂!我要见你们的师傅——粉面大秃驴。”那两个人没有搭理他,反而说:“我们的师傅岂是你这个毛猴想见就见的!”孙悟空听了,心中很是愤怒,心想:当初我大闹天宫时,怕过谁!而现在却让这两个毛孩训斥,哼!给你们点厉害瞧瞧。接着,他就掏出金箍棒朝那两个人砸去。可是谁知刚砸到他们面前,却被一道光给挡了回来。原来他们的面前都有一道防护层。“哼!21世纪还用武力解决问题,白痴!”他们不懈的说,“21世纪是智慧的时代,不过,看你是孙悟空的面子上,你只要答对我们的问题,我便放你进去见我们的师傅。”悟空听了,无奈的点了点头,看来只有这样了。“好,猴头,你听好了!这里有一个桃子,我们以下列的方式对它进行变换:

① 开始时,只有一个桃子;
② 每一次变换,把其中的桃子变成桃子和梨,其中的梨变成桃子。

我们用‘T’表示桃子,用‘L’表示梨,则经过无数次的变换,我们得到如下字符串“TLTTLTLTTLTTLTLTTLT……”。现在你的任务是:每次给你n个询问,每个询问为:在区间a和b之间有多少个桃子。”孙悟空听了傻了眼,他一个从石头里蹦出来的猴子,哪会这么多东西。可是他必须要去见泰山宗,怎么办呢?看来只有求助于你们了。

Input
第一行是一个整数n,表示有n次提问,后面有n行,每行有两个整数a和b,用空格隔开。

Output
共n行,每行有一个回答,表示在这个区间内有多少个桃子。

Sample Input
1
2 8

Sample Output
4

【数据规模】
  对于100%的数据
  1 < = n <= 5000
  1 <= a <= b < 2^63

 

当时实在没什么头绪,就写了一个朴素模拟,就发现是什么斐波拉契数列,也就是从第三项起a[n]=a[n-1]+a[n-2],可是知道了是这个东西也些不出来(晕~),最后还是交的朴素程序,只得了40左右

现通过一个预处理,生成1~91(92的时候长度就溢出了,也就是超过了2^63),要处理一个f[i]表示1~i中桃子的个数,用len[i]表示1~i的长度

答案就相当于用前缀和的方式,[l,r]之间的桃子个数就等于[1,r]的减去[1,l-1]的,用一个find函数实现

find带两个参数x和nn,表示在前nn个斐波拉契数列中找到x,并返回桃子个数
如果x刚好等于len[nn],就返回f[nn]
如果x小于len[nn],那么就是相同子问题,返回find(x,nn-1)
剩下就是x大于len[nn]的情况了,由于第n项的组合是按照第nn-1项+第nn-2项组合起来的,而此时x落在了第n-2项所在区间内,所以x-len[nn-1]表示x在nn-2项中的位置并在里面找到,即find(x-len[nn-1],nn-2),然后再加上前面nn-1项所有的桃子数,最后返回f[nn-1]+find(x-len[nn-1],nn-2)

还有细节就是数据的输入输出由于在long long 范围,所以最好用cin,cout输入输出

 

C++ Code

/*
C++ Code
http://oijzh.cnblogs.com
*/
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
#define MAXN 5010

typedef long long LL;
int n;
LL f[100],len[100];
LL l,r;

void predoing()
{
    len[1]=1;len[2]=2;
    f[1]=1;f[2]=1;
    for(int i=3;i<=91;i++)
    {
        f[i]=f[i-1]+f[i-2];
        len[i]=len[i-1]+len[i-2];
    }
}

LL find(LL x,int nn)
{
    if(!x)return 0;
    if(x==len[nn])return f[nn];
    else if(x<=len[nn-1]) return find(x,nn-1);
    else return f[nn-1]+find(x-len[nn-1],nn-2);
}

int main()
{
    freopen("monkey.in","r",stdin);
    freopen("monkey.out","w",stdout);
    scanf("%d",&n);
    predoing();
    for(int i=1;i<=n;i++)
    {
        cin>>l>>r;
        cout<<find(r,91)-find(l-1,91)<<endl;
    }
    return 0;
}

 

 

posted @ 2012-10-19 17:40  jiangzh  阅读(372)  评论(0编辑  收藏  举报