【数值数论】【Fibonacci数列】悟空学艺

【题目描述】
    说当初大闹天宫的猴头反斗精——孙悟空来到了21世纪。当他通过时空隧道来到21世纪时才发现世界发生了翻天覆地的变化。于是他决定来中国的泰山学艺。他在海南腾云驾雾来到泰山脚下,谁知脚下却有两个人把守。他走上前对他们说:“喂!我要见你们的师傅——粉面大秃驴。”那两个人没有搭理他,反而说:“我们的师傅岂是你这个毛猴想见就见的!”孙悟空听了,心中很是愤怒,心想:当初我大闹天宫时,怕过谁!而现在却让这两个毛孩训斥,哼!给你们点厉害瞧瞧。接着,他就掏出金箍棒朝那两个人砸去。可是谁知刚砸到他们面前,却被一道光给挡了回来。原来他们的面前都有一道防护层。“哼!21世纪还用武力解决问题,白痴!”他们不懈的说,“21世纪是智慧的时代,不过,看你是孙悟空的面子上,你只要答对我们的问题,我便放你进去见我们的师傅。”悟空听了,无奈的点了点头,看来只有这样了。“好,猴头,你听好了!这里有一个桃子,我们以下列的方式对它进行变换:
    ①开始时,只有一个桃子;
    ②每一次变换,把其中的桃子变成桃子和梨,其中的梨变成桃子。 
    我们用‘T’表示桃子,用‘L’表示梨,则经过无数次的变换,我们得到如下字符串“TLTTLTLTTLTTLTLTTLT……”。现在你的任务是:每次给你n个询问,每个询问为:在区间a和b之间有多少个
桃子。”孙悟空听了傻了眼,他一个从石头里蹦出来的猴子,哪会这么多东西。可是他必须要去见泰山宗,怎么办呢?看来只有求助于你们了。
【输入格式】
    第一行是一个整数n,表示有n次提问,后面有n行,每行有两个整数a和b,用空格隔开。
    对于100%的数据 
    1<=n<=5000 
    1<=a<=b<2^63
【输出格式】
    共n行,每行有一个回答,表示在这个区间内有多少个桃子。
【输入样例】
1
2 8
【输出样例】
4
 
    这道题,照规则模拟一下,发现是一个斐波那契数列。如下:
字符串:                                          总长:               T个数: L个数
T                                                 1                    1 0
TL                                                2                    1 1
TLT                                               3                    2 1
TLTTL                                             5                    3 2
TLTTLTLT                                          8                    5 3
TLTTLTLTTLTTL                                     13                   8 5
TLTTLTLTTLTTLTLTTLTLT                             21                   13 8
    这样,我们发现这是一个斐波那契数列。不论是长度,还是T个数,甚到是字符串本身,甚至于L的个数,都满足f[i]=f[i-1]+f[i-2]。
    于是,对于一个区间[a,b],我们可以这样算出答案:ans=Cal(b)-Cal(a-1)。
    如何计算呢
对于区间[a, b]计算b和计算a同理
以计算b为例
设a为斐波那契数列 则b可以拆分为k个斐波那契数的和
而T的个数就是那k个斐波那契数的前一项的和

轻松解决…


代码如下:

#include <cstdio>
#include <cstdlib>
#include <iomanip>
#include <cstring>
using namespace std;

typedef  long long ll;
ll F[10086];
ll T_R;
ll T_L;
int N;

void init_file()
{
	freopen("Monkey.in", "r", stdin);
	freopen("Monkey.out", "w", stdout);
}

void read_data()
{
	F[1] = 1;
	F[2] = 1;
	for(int i = 3; i <= 100; i++)
		F[i] = F[i - 1] + F[i - 2];
	scanf("%d", &N);
}

ll cal_R(ll x)
{
	ll X = x;
	for(int i = 92; i >= 2; i--) //至于为什么是92……打个数列的表它在93爆了…∴是92 
	{
		if (X >= F[i])
		{
			X -= F[i];
			T_R += F[i - 1];
		}
	}
}

ll cal_L(ll x)
{
	ll X = x;
	for(int i = 92; i >= 2; i--)
	{
		if (X >= F[i])
		{
			X -= F[i];
			T_L += F[i - 1];
		}
	}
}

void work()
{
		while(N--)
		{
			T_L = 0;
			T_R = 0;
			ll L; ll R;
			scanf("%I64d%I64d", &L, &R);
			cal_R(R);
			cal_L(L - 1);
			printf("%I64d\n", T_R - T_L);
		}
}

int main()
{
	init_file();
	read_data();
	work();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值