是一个典型的找规律的题目。
题目描述
小 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:保证 aia_iai , bib_ibi 均为某一个月出生的兔子中标号最大的一对兔子。例如,对 于前六个月,标号最大的兔子分别是 1, 2, 3, 5, 8, 13。
特殊性质 2:保证 ∣ai−bi∣≤1|a_i-b_i|\le 1∣ai−bi∣≤1 。
可以看出一个很明显的规律。我们设定第i个月出生f(i)只兔子,那么很显然在第i个月能生小兔子的是在第i-2个月就存在的小兔子。所以有f(i)=f(i-1)+f(i-2)
好像一个斐波那契
好吧就是一个斐波那契。
我们设定第i个月出生的第j只兔子的编号为f(i-1)+j很明显吧。那么他的父亲就是j
j<f(i-1)
那么可以推出任何一只编号为x的兔子都有f(i)<x<=f(i+1);
可以肯定他的父亲的编号比他的编号小,且两个的编号一定是一个斐波那契数,而且肯定在比他小的但是是最大斐波那契数。
那么就可以用二分查找了。
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; int n; long long a[200]; long long x,y; void ga(long long x,long long y){ } int main(){ cin>>n; a[0]=1;a[1]=1; for(int i=2;i<=61;i++){ a[i]=a[i-1]+a[i-2]; } for(int i=1;i<=n;i++){ cin>>x>>y; while(x!=y){ if(y<x) swap(x,y); int l=1,r=61; int mid; while(l<=r){ mid=(l+r)/2; if(a[mid]<y) l=mid+1; else r=mid-1; } y-=a[l-1]; } cout<<x<<endl; } }