【斐波拉契数列】悟空学艺(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; }