【递推】悟空学艺

转自:http://hi.baidu.com/wengweijian/item/5ca4b5a320f7e5eb14329b60

【题目】

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

① 开始时,只有一个桃子;

② 每一次变换,把其中的桃子变成桃子和梨,其中的梨变成桃子。

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

输入:

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

输出:

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

【样例】

输入   1

       2 8

输出   4

【数据规模】

对于100%的数据

     1<=n<=5000     

        1<=a<=b<2^63

【分析】

手写几次变换以后就可以发现:

字符串:                                  总长:           T个数:

T                                                                 1                     1

TL                                                               2                     1

TLT                                                             3                     2

TLTTL                                                          5                     3

TLTTLTLT                                                     8                     5

TLTTLTLTTLTTL                                            13                   8

TLTTLTLTTLTTLTLTTLTLT                              21                   13

TLTTLTLTTLTTLTLTTLTLTTLTTLTLTTLTTL       34                   21    


第x次变化以后串的总长为Fibonacci的第x+1项,T的个数为Fibonacci的第x项

在观察还可以发现字符串本身也是S(i)=S(i-1)+S(i-2)

于是设前i个中T的个数为f[i],则答案为f[b]-f[a-1]

那f[i]如何求呢???

首先:设i=A(x1)+A(x2)+A(x3)……A(xm)          (A(x1),A(x2),A(x3),A(xm)均为Fibonacci数列的某一项)

那么f[i]=A(x1-1)+A(x2-1)+A(x3-1)……A(xm-1)  (A(x1-1)为Fibonacci数列中A(x1)的前一项)

再者我们可以求出A(93)>2^63了,那么Fibonacci预处理到92就可以了!


【代码】

#include<cstdio>
#include<iostream>
using namespace std;

 long long s[100]={0},t[100]={0},n,a,b;

long long get(long long x)
{
	long long ans=0;
	for (long long i=92;i>=1;i--)
	 {
	 	if (s[i]<=x)
	 	{
	 		x-=s[i];
	 		ans+=t[i];
	 	} 		
	 }
	return ans;
}


int main()
{
 freopen("monkey.in","r",stdin);
 freopen("monkey.out","w",stdout);
  cin>>n;
  s[1]=1;s[2]=1;
  t[1]=0;t[2]=1;
  for (long long  i=3;i<=93;i++) s[i]=s[i-1]+s[i-2];
  for (long long  i=3;i<=93;i++) t[i]=t[i-1]+t[i-2];
  for (long long  i=1;i<=n;i++)
   {
    cin>>a>>b;
   	long long x1=get(a-1);
   	long long x2=get(b);
   	cout<<x2-x1<<endl;
   }
 return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值