题目传送门


题目描述

小$C$养了一些很可爱的兔子。
有一天,小$C$突然发现兔子们都是严格按照伟大的数学家斐波那契提出的模型来进行繁衍:一对兔子从出生后第二个月起,每个月刚开始的时候都会产下一对小兔子。我们假定,在整个过程中兔子不会出现任何意外。
小$C$把兔子按出生顺序,把兔子们从$1$开始标号,并且小$C$的兔子都是$1$号兔子和$1$号兔子的后代。如果某两对兔子是同时出生的,那么小$C$会将父母标号更小的一对优先标号。
如果我们把这种关系用图画下来,前六个月大概就是这样的:

其中,一个箭头$A\rightarrow B$表示$A$是$B$的祖先,相同的颜色表示同一个月出生的兔子。
为了更细致地了解兔子们是如何繁衍的,小$C$找来了一些兔子,并且向你提出了$m$个问题:她想知道关于每两对兔子$a_i$和$b_i$,他们的最近公共祖先是谁。你能帮帮小$C$吗?

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


输入格式

输入第一行,包含一个正整数$m$。
输入接下来$m$行,每行包含$2$个正整数,表示$a_i$和$b_i$。


输出格式

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


样例

样例输入1:

5
1 1
2 3
5 7
7 13
4 12

样例输出1:

1
1
2
2
4

样例输入2:

10
13 5
13 6
13 7
13 8
13 9
13 10
13 11
13 12
13 13
13 14

样例输出2:

5
1
2
1
1
2
1
1
13
1


数据范围与提示

子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。
每个测试点的数据规模及特点如下表:
测试点     $m$                      $a_i,b_i$           特殊性质$1$           特殊性质$2$
  $1$          $\leqslant 11$                  $\leqslant 15$                  $\surd$                         $\surd$
  $2$          $\leqslant 12$                  $\leqslant 15$                  $\times$                         $\times$
  $3$          $\leqslant 13$                  $\leqslant 1000$             $\surd$                         $\times$
  $4$          $\leqslant 14$                  $\leqslant 1000$             $\times$                         $\times$
  $5$          $\leqslant 1005$             $\leqslant{10}^6$                $\surd$                        $\times$
  $6$          $\leqslant 1006$             $\leqslant{10}^6$                $\times$                        $\surd$
  $7$          $\leqslant 1007$             $\leqslant{10}^6$                $\times$                        $\times$
  $8$          $\leqslant 300008$        $\leqslant{10}^{12}$              $\surd$                        $\times$
  $9$          $\leqslant 300009$        $\leqslant{10}^{12}$              $\times$                        $\surd$
  $10$        $\leqslant 300010$        $\leqslant{10}^{12}$              $\times$                        $\times$

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


题解

考场上$20$分钟切掉这道题,我感觉还是蛮爽的。

$20\%$算法:

直接手动打表,注意$14$是$1$的儿子,而$15$则是$2$的儿子,挺费眼睛的,而且一开始我打了一个表还没打对……

时间复杂度:$\Theta(m)$。

期望得分:$20$分。

$40\%$算法:

直接暴力建树,每次询问都暴力把这棵树重新建一遍来找父亲。

我觉得写这种方法的就是$\times \times \times$,不用管他……

时间复杂度:$\Theta(m\times {|a|}^2\times \log|a|)$($|a|$表示$a_i,b_i$的值域)。

期望得分:$40$分。

$60\%$算法:

考虑$QJ$两个特殊情况:

特殊情况$1$:

  某一个月出生的标号最大的兔子就是斐波那契数列中的一项,画一张图,如下:

  

  我们便会惊喜的发现如果这两只兔子同是斐波那契数列的奇数项或偶数项,那么它们的最近公共祖先就是他们当中较小的那个;否则,它们的最近公共祖先为$1$。

特殊情况$2$:

  如果两只兔子的标号的绝对值等于$1$,则他们的最近公共祖先一定为$1$。

$70\%$算法:

可能细心的你会发现,一个节点一定小于自己儿子的一半,所以我们可以暴力网上找,最多有$\log i$层。

时间复杂度:$\Theta(n+m\log n)$。

期望得分:$70$分。

$100\%$算法:

在考场上,我惊喜的发现了一个规律,一个节点的减去比它小的那个斐波那契数就是他的父亲节点,所以我们可以每次让两个点中更小的那个暴力往上抬,直到相同为止即可。

时间复杂度:$\Theta(60\times m)$。

期望得分:$100$分。


代码时刻

$20\%$算法:

#include<bits/stdc++.h>
using namespace std;
int Map[16][16]={
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
0,1,2,1,1,2,1,2,1,1,2,1,1,2,1,2,
0,1,1,3,1,1,1,1,3,1,1,3,1,1,1,1,
0,1,1,1,4,1,1,1,1,1,1,1,4,1,1,1,
0,1,2,1,1,5,1,2,1,1,2,1,1,5,1,2,
0,1,1,1,1,1,6,1,1,1,1,1,1,1,1,1,
0,1,2,1,1,2,1,7,1,1,2,1,1,2,1,2,
0,1,1,3,1,1,1,1,8,1,1,3,1,1,1,1,
0,1,1,1,1,1,1,1,1,9,1,1,1,1,1,1,
0,1,2,1,1,2,1,2,1,1,10,1,1,2,1,2,
0,1,1,3,1,1,1,1,3,1,1,11,1,1,1,1,
0,1,1,1,4,1,1,1,1,1,1,1,12,1,1,1,
0,1,2,1,1,5,1,2,1,1,2,1,1,13,1,2,
0,1,1,1,1,1,1,1,1,1,1,1,1,1,14,1,
0,1,2,1,1,2,1,2,1,1,2,1,1,2,1,15};
int main()
{
int m;
scanf("%d",&m);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",Map[a][b]);
}
return 0;
}

$60\%$算法:

#include<bits/stdc++.h>
using namespace std;
int m;
long long fi[60];
int getnum(long long x)
{
int res;
for(int i=1;i<=59;i++)if(fi[i]==x){res=i;break;}
return res;
}
int main()
{
scanf("%d",&m);
fi[0]=fi[1]=1;
for(int i=2;i<=59;i++)
fi[i]=fi[i-1]+fi[i-2];
for(int i=1;i<=m;i++)
{
long long a,b;
scanf("%lld%lld",&a,&b);
if(a==b){printf("%lld\n",a);continue;}
if(a-b==1||b-a==1){puts("1");continue;}
int numa=getnum(a),numb=getnum(b);
if(numa!=-1&&numb!=-1&&(numa&1)==(numb&1))printf("%lld\n",min(a,b));
else puts("1");
}
return 0;
}

$70\%$算法:

#include<bits/stdc++.h>
using namespace std;
int m;
struct rec
{
int nxt;
int to;
}e[1000001];
int head[1000001],cnt;
int t[1000001],tot=1,tmp,depth[1000001],fa[1000001][23];
bool flag;
void add(int st,int to)
{
e[++cnt].to=to;
e[cnt].nxt=head[st];
head[st]=cnt;
}
void build()
{
t[1]=1;
for(int x=1;x<30;x++)
{
tmp=tot;
for(int i=1;i<=tot;i++)
{
t[i]++;
if(t[i]>1)add(i,++tmp);
if(tmp>=1000000)return;
}
tot=tmp;
}
}
void dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
depth[e[i].to]=depth[x]+1;
fa[e[i].to][0]=x;
for(int j=1;j<=21;j++)
fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
dfs(e[i].to);
}
}
int LCA(int x,int y)
{
if(depth[x]>depth[y])swap(x,y);
for(int i=21;i>=0;i--)
if(depth[fa[y][i]]>=depth[x])y=fa[y][i];
if(x==y)return x;
for(int i=21;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int main()
{
scanf("%d",&m);
build();
depth[1]=1;
dfs(1);
while(m--)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",LCA(a,b));
}
return 0;
}

$100\%$算法:

#include<bits/stdc++.h>
using namespace std;
int m;
long long fi[61];
long long LCA(long long x,long long y)
{
while(1)
{
if(x==y)return x;
if(x>y){for(int i=1;i<=65;i++)if(fi[i]<x&&fi[i+1]>=x){x-=fi[i];break;}}
else for(int i=1;i<=65;i++)if(fi[i]<y&&fi[i+1]>=y){y-=fi[i];break;}
}
}
int main()
{
fi[1]=fi[2]=1;
for(int i=3;i<=60;i++)
fi[i]=fi[i-1]+fi[i-2];
scanf("%d",&m);
while(m--)
{
long long a,b;
scanf("%lld%lld",&a,&b);
printf("%lld\n",LCA(a,b));
}
return 0;
}
 

rp++

[洛谷P3938]:斐波那契(fibonacci)(数学)的更多相关文章

  1. 洛谷P3938 斐波那契

    题目戳 题目描述 小 C 养了一些很可爱的兔子. 有一天,小 C 突然发现兔子们都是严格按照伟大的数学家斐波那契提出的模型来进行 繁衍:一对兔子从出生后第二个月起,每个月刚开始的时候都会产下一对小兔子 ...

  2. 洛谷 P1306 斐波那契公约数

    洛谷 P1306 斐波那契公约数 题目描述 对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第n项和第m项的最大公约数是多少? ...

  3. 洛谷P1962 斐波那契数列【矩阵运算】

    洛谷P1962 斐波那契数列[矩阵运算] 题目背景 大家都知道,斐波那契数列是满足如下性质的一个数列: • f(1) = 1 • f(2) = 1 • f(n) = f(n-1) + f(n-2) ( ...

  4. 洛谷 P1306 斐波那契公约数 解题报告

    P1306 斐波那契公约数 题意:求\(Fibonacci\)数列第\(n\)项和第\(m\)项的最大公约数的最后8位. 数据范围:\(1<=n,m<=10^9\) 一些很有趣的性质 引理 ...

  5. 洛谷——P1306 斐波那契公约数

    P1306 斐波那契公约数 题目描述 对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第n项和第m项的最大公约数是多少? 输入输 ...

  6. 洛谷P1962 斐波那契数列 || P1349 广义斐波那契数列[矩阵乘法]

    P1962 斐波那契数列 大家都知道,斐波那契数列是满足如下性质的一个数列: • f(1) = 1 • f(2) = 1 • f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 为整数 ...

  7. 洛谷P1755 斐波那契的拆分

    题目背景 无 题目描述 已知任意一个正整数都可以拆分为若干个斐波纳契数,现在,让你求出n的拆分方法 输入输出格式 输入格式: 一个数t,表示有t组数据 接下来t行,每行一个数n(如题) 输出格式: t ...

  8. 洛谷——P2626 斐波那契数列(升级版)矩阵

    题目背景 大家都知道,斐波那契数列是满足如下性质的一个数列: • f(1) = 1 • f(2) = 1 • f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 为整数). 题目描述 ...

  9. 洛谷 P2626 斐波那契数列(升级版)

    题目背景 大家都知道,斐波那契数列是满足如下性质的一个数列: • f(1) = 1 • f(2) = 1 • f(n) = f(n-1) + f(n-2) (n ≥ 2 且 n 为整数). 题目描述 ...

随机推荐

  1. 自己手动用原生实现bind/call/apply

    自己手动用原生实现bind/call/apply:https://www.cnblogs.com/LHLVS/p/10595784.html

  2. C++中的字符串类

    1,本文分析 C++ 中的字符串,C 语言中的字符串利用的是 C 语言中的字符数组,  在 C 语言中没有真正意义上的字符串,利用了字符数组表示了字符串,最初设  计 C 语言仅仅是为了开发 Unix ...

  3. js实现计算器效果

    <!DOCTYPE html> <html> <!-- Created using jsbin.com Source can be edited via http://j ...

  4. 基于BufferedImage的图像滤镜演示

    package chapter2; import javax.imageio.ImageIO;import javax.swing.*;import javax.swing.filechooser.F ...

  5. scala学习笔记(7)

    1.包 --------------------------------------- Scala中的包和Java或者C++中命名空间的目的是相同的:管理大型程序中的名称. package a{ pa ...

  6. Vue实现二级菜单的显示与隐藏

    <html> <head> <title>Vue实现二级菜单的显示与隐藏</title> <script src="vue.js&quo ...

  7. CF1260C Infinite Fence 题解(扩欧)

    题目地址 CF1260C 题目大意 现有\(10^{100}\)块木板需要涂漆,第x块如果是x是a的倍数,则涂一种颜色,是b的倍数,则涂另一种颜色.如果既是a又是b的倍数,那么两种颜色都可以涂:如果连 ...

  8. ztree 获取CheckBox选中节点时,不获取选中上级父节点

    //将第三个参数改为false,表示不去勾选父节点下的所有子节点 zTreeObj.checkNode(node, true, false); setting.check.chkboxType = { ...

  9. Django【第26篇】:中介模型以及优化查询以及CBV模式

    中介模型以及优化查询以及CBV模式 一.中介模型:多对多添加的时候用到中介模型 自己创建的第三张表就属于是中介模型 class Article(models.Model): ''' 文章表 ''' t ...

  10. vuex使用方法

    vuex是一个专门为vue.js设计的集中式状态管理架构.状态?我把它理解为在data中的属性需要共享给其他vue组件使用的部分,就叫做状态.简单的说就是data中需要共用的属性.比如:我们有几个页面 ...