洛谷3938 斐波那契

79 篇文章 0 订阅
76 篇文章 0 订阅

标签:数论,LCA,树

http://www.yjjr.org/nd.jsp?id=14#_np=2_327

题目背景

大样例下发链接:http://pan.baidu.com/s/1c0LbQ2 密码:jigg

题目描述

小 C 养了一些很可爱的兔子。 有一天,小 C 突然发现兔子们都是严格按照伟大的数学家斐波那契提出的模型来进行 繁衍:一对兔子从出生后第二个月起,每个月刚开始的时候都会产下一对小兔子。我们假定,在整个过程中兔子不会出现任何意外。

小 C 把兔子按出生顺序,把兔子们从1 开始标号,并且小 C 的兔子都是 1 号兔子和 1 号兔子的后代。如果某两对兔子是同时出生的,那么小 C 会将父母标号更小的一对优先标号。

如果我们把这种关系用图画下来,前六个月大概就是这样的:


其中,一个箭头 A → B 表示 A 是 B 的祖先,相同的颜色表示同一个月出生的兔子。

为了更细致地了解兔子们是如何繁衍的,小 C 找来了一些兔子,并且向你提出了 m 个 问题:她想知道关于每两对兔子 aia_iai​ 和 bib_ibi​ ,他们的最近公共祖先是谁。你能帮帮小 C 吗?

一对兔子的祖先是这对兔子以及他们父母(如果有的话)的祖先,而最近公共祖先是指 两对兔子所共有的祖先中,离他们的距离之和最近的一对兔子。比如,5 和 7 的最近公共祖 先是 2,1 和 2 的最近公共祖先是 1,6 和 6 的最近公共祖先是 6。

输入输出格式

输入格式:

从标准输入读入数据。 输入第一行,包含一个正整数 m。 输入接下来 m 行,每行包含 2 个正整数,表示 aia_iai​ 和 bib_ibi​ 。

输出格式:

输出到标准输出中。 输入一共 m 行,每行一个正整数,依次表示你对问题的答案。

输入输出样例

输入样例#1: 复制

5

1 1

2 3

5 7

7 13

4 12

输出样例#1: 复制

1

1

2

2

4

说明

【数据范围与约定】 子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解 决一部分测试数据。 每个测试点的数据规模及特点如下表:


特殊性质 1:保证 aia_iai​, bib_ibi​ 均为某一个月出生的兔子中标号最大的一对兔子。例如,对 于前六个月,标号最大的兔子分别是 1, 2, 3, 5, 8, 13。

特殊性质 2:保证 ∣ai−bi∣≤1|a_i-b_i|\le1∣ai​−bi​∣≤1。

 

这题应该略大于D2T1难度,结论题:儿子节点的序号=父亲节点的序号+小于该儿子节点的斐波那契数

所以父亲节点的序号=儿子节点的序号-小于该儿子节点的斐波那契数

这个结论我推了一个小时,真是zz啊

然后可以根据这个结论做LCA,两者同时往上跳找到相同的祖先节点

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#ifdef WIN32
#define LL "%I64d\n"
#else
#define LL "%lld\n"
#endif
using namespace std;
inline ll read()
{
    ll f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

const int maxx=95;
ll f[maxx],m,now;
int main()
{
	f[1]=f[2]=1;
	rep(i,3,maxx)f[i]=f[i-1]+f[i-2];
	//rep(i,1,maxx)cout<<f[i]<<' ';
//	cout<<endl;
	m=read();
	rep(i,1,m){
		ll x=read(),y=read();
		while(x!=y){
			if(x>y)swap(x,y);
			now=lower_bound(f+1,f+1+maxx,y)-f;
			now--;
			if(f[now]==y)now--;
			y-=f[now];//cout<<now<<' '<<f[now]<<' '<<x<<' '<<y<<endl;
		}
		printf(LL,x);
    }
    return 0;
}
			
			



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值