题目

题目描述

小 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
  2. 1 1
  3. 2 3
  4. 5 7
  5. 7 13
  6. 4 12

输出

  1. 1
  2. 1
  3. 2
  4. 2
  5. 4

说明

题解

分析

首先考虑70%的数据,

每天新出生的兔子数目一定是f[i],这个很容易计算得出

然后发现,这f[i]只兔子的父亲一定是1~f[i],于是模拟这个过程,做一遍LCA即可

再考虑100%的数据,

n达到int以上,无法模拟,

,发现第s[i]+1只兔子父亲肯定是1,第s[i]+2只兔子父亲肯定是2,第只兔子父亲一定是

于是有思路:二分s数组,使得,这时候a的父亲就是

这样的话一开始a是大于s[i]的,减过之后就小于s[i]了,至少折半,效率至多是O(logn),感觉挺快的

对b也做一遍,记录他们的“祖先历程”,然后用两个指针找一下公共祖先就可以了

实际上我是处理到的,如果小于就直接做倍增了,这样可能快一些,不过事实证明是差不多的

代码

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<vector>
  6. #define ll long long
  7. #define maxn 1000005
  8. #define lo 21
  9. using namespace std;
  10. inline ll read() {
  11. ll x=0,w=1;
  12. char ch=getchar();
  13. while(ch!='-'&&(ch<'-'||ch>'9')) ch=getchar();
  14. if(ch=='-') w=-1,ch=getchar();
  15. while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
  16. return x*w;
  17. }
  18. int fa[lo][maxn];
  19. ll M=1e12+50;
  20. ll d[maxn];
  21. ll f[maxn],sum[maxn];
  22. vector<ll> fath[2];
  23. int lca(int,int);
  24. void work(ll,int);
  25. int main() {
  26. freopen("fibonacci.in","r",stdin);
  27. freopen("fibonacci.out","w",stdout);
  28. f[0]=f[1]=f[2]=1;
  29. sum[0]=1;sum[1]=2;sum[2]=3;
  30. fa[0][2]=fa[0][3]=1;
  31. d[2]=d[3]=1;
  32. register int i=3,j=0;
  33. while(1)
  34. {
  35. f[i]=f[i-1]+f[i-2];
  36. sum[i]=sum[i-1]+f[i];
  37. if(sum[i]>M) break;
  38. i++;
  39. }
  40. i=3;
  41. while(1)
  42. {
  43. for(j=sum[i-1]+1; j<=sum[i]&&j<maxn; j++)
  44. {
  45. fa[0][j]=j-sum[i-1]; /*根据规律找父亲节点*/
  46. d[j]=d[j-sum[i-1]]+1;
  47. }
  48. if(j>=maxn) break;
  49. i++;
  50. }
  51. for(int k=1; k<lo; k++) for(int i=1; i<maxn; i++) fa[k][i]=fa[k-1][fa[k-1][i]];
  52. int T=read();
  53. for(register int i=1;i<=T;++i)
  54. {
  55. ll a=read(),b=read();
  56. if(a==b)
  57. {
  58. printf("%lld\n",a);
  59. continue;
  60. }
  61. if(a<maxn&&b<maxn) /*小于1e6的数据直接做lca*/
  62. {
  63. printf("%d\n",lca(a,b));
  64. }
  65. else
  66. {
  67. fath[0].clear(),fath[1].clear();
  68. work(a,0);
  69. work(b,1);
  70. int i=0,j=0,flag=0;
  71. while(i<fath[0].size()&&j<fath[1].size()) /*lca*/
  72. {
  73. if(fath[0][i]==fath[1][j])
  74. {
  75. printf("%lld\n",fath[1][j]);
  76. flag=1;
  77. break;
  78. }
  79. if(fath[0][i]>fath[1][j]) i++;
  80. else j++;
  81. }
  82. if(!flag)
  83. {
  84. a=fath[0][fath[0].size()-1],b=fath[1][fath[1].size()-1];
  85. printf("%d\n",lca(a,b));
  86. }
  87. }
  88. }
  89. return 0;
  90. }
  91. int lca(int x,int y)
  92. {
  93. if(d[x]<d[y]) swap(x,y);
  94. for(register int k=d[x]-d[y],p=0; k; p++,k>>=1) if(k&1) x=fa[p][x];
  95. if(x==y) return x;
  96. for(register int k=lo-1; k>=0; k--) if(fa[k][x]!=fa[k][y]) x=fa[k][x],y=fa[k][y];
  97. return fa[0][x];
  98. }
  99. void work(ll a,int t) /*对于大于1e6的数据找祖先*/
  100. {
  101. ll x=a;
  102. fath[t].push_back(x);
  103. while(1)
  104. {
  105. if(x<maxn) break;
  106. int L=0,R=60;
  107. while(R-L>1)
  108. {
  109. int mid=(L+R)/2;
  110. if(sum[mid]<x) L=mid;
  111. else R=mid;
  112. }
  113. if(sum[R]<x) x=x-sum[R];
  114. else x=x-sum[L];
  115. fath[t].push_back(x);
  116. }
  117. }

【题解】斐波拉契 luogu3938的更多相关文章

  1. python迭代器实现斐波拉契求值

    斐波那契数列(Fibonacci sequence),又称黄金分割数列,也称为"兔子数列":F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*).例 ...

  2. 斐波拉契数列加强版——时间复杂度O(1),空间复杂度O(1)

    对于斐波拉契经典问题,我们都非常熟悉,通过递推公式F(n) = F(n - ) + F(n - ),我们可以在线性时间内求出第n项F(n),现在考虑斐波拉契的加强版,我们要求的项数n的范围为int范围 ...

  3. 剑指offer三: 斐波拉契数列

    斐波拉契数列是指这样一个数列: F(1)=1; F(2)=1; F(n)=F(n-1)+F(n); public class Solution { public int Fibonacci(int n ...

  4. ACM/ICPC 之 数论-斐波拉契●卢卡斯数列(HNNUOJ 11589)

    看到这个标题,貌似很高大上的样子= =,其实这个也是大家熟悉的东西,先给大家科普一下斐波拉契数列. 斐波拉契数列 又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.34.… ...

  5. 关于斐波拉契数列(Fibonacci)

    斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10 ...

  6. 剑指offer-第二章算法之斐波拉契数列(青蛙跳台阶)

    递归与循环 递归:在一个函数的内部调用这个函数. 本质:把一个问题分解为两个,或者多个小问题(多个小问题相互重叠的部分,会存在重复的计算) 优点:简洁,易于实现. 缺点:时间和空间消耗严重,如果递归调 ...

  7. 剑指offer-面试题9.斐波拉契数列

    题目一:写一个函数,输入n,求斐波拉契数列的第n项. 斐波拉契数列的定义如下: { n=; f(n)={ n=; { f(n-)+f(n-) n>; 斐波拉契问题很明显我们会想到用递归来解决: ...

  8. 【斐波拉契+数论+同余】【ZOJ3707】Calculate Prime S

    题目大意: S[n] 表示 集合{1,2,3,4,5.......n} 不存在连续元素的子集个数 Prime S 表示S[n]与之前的所有S[i]互质; 问 找到大于第K个PrimeS 能整除X 的第 ...

  9. C语言数据结构----递归的应用(斐波拉契数列、汉诺塔、strlen的递归算法)

    本节主要说了递归的设计和算法实现,以及递归的基本例程斐波拉契数列.strlen的递归解法.汉诺塔和全排列递归算法. 一.递归的设计和实现 1.递归从实质上是一种数学的解决问题的思维,是一种分而治之的思 ...

随机推荐

  1. 对标印度的PostMan,一款中国接口测试软件的崛起

    对于我们开发者,Api接口调试一定不陌生.包括我在内,之前进行Api调试时,一直使用的是一款印度的软件Postman.记得刚入手的时候,由于该款软件缺乏中文版本,上手一直比较慢,而且还至少存在如下几个 ...

  2. HDU - 1789 Doing Homework again(贪心) ~~~学了一波sort对结构体排序

    题目中因为天数和分数是对应的,所以我们使用一个结构体来存分数和截止如期. 一开始做这道题的时候,很自然的就想到对天数排序,然后天数一样的分数从大到小排序,最后WA了之后才发现没有做到"舍小取 ...

  3. Visual Lab Online —— Alpha版本发布声明

    Visual Lab Online -- Alpha版本发布声明 项目 内容 班级:北航2020春软件工程 博客园班级博客 作业:Alpha阶段发布声明 发布声明 目录 Visual Lab Onli ...

  4. SE_Work3_结队项目

    项目 内容 课程:北航-2020-春-软件工程 博客园班级博客 要求:求交点个数 结对项目作业 班级:005 Sample GitHub地址 intersect 北航网盘地址 SE结队项目 1. PS ...

  5. 还在手动部署jar包吗?快速掌握Jenkins安装,教你使用Jenkins实现持续交付

    Jenkins Jenkins: 开源软件项目 基于Java开发的一种持续集成工具 用于监控持续重复的工作 旨在提供一个开放易用的软件平台, 便于软件的持续集成 基于Docker安装Jenkins 与 ...

  6. Java_集合之一

    1.Collection集合 1.1数组和集合的区别[理解] 相同点 都是容器,可以存储多个数据 不同点 数组的长度是不可变的,集合的长度是可变的 数组可以存基本数据类型和引用数据类型 集合只能存引用 ...

  7. [Django框架 - 注意事项,安装,项目搭建,小白必会三板斧]

    [Django框架 - 注意事项,安装,项目搭建,小白必会三板斧] 想要正常运行django项目所需要知道的注意事项 1. 计算机名称不能有中文,不然bug在哪儿你都不知道! 2. 项目名和py文件名 ...

  8. for 循环语句 (enumerate枚举,据说直接写出索引值)

    for i in ***: 今天上课看到alex用了 for index,i in enumerate(list): print(index,i) (enumerate好像可以设置开头序号enumer ...

  9. java基础——何为方法

    方法 java中方法时语句的集合,他们在一起执行一个功能 方法时解决一类问题的步骤的有序组合 方法包含于与类或者对象中 方法在程序中被创建,在其他地方被引用 设计方法的原则:保持其原子性. 就是一个方 ...

  10. R语言执行脚本的几种命令

    R CMD BATCH 和 Rscript 使用前都要先添加环境变量 把 C:\Program Files\R\R-3.3.0\bin; 加到"系统变量"的Path 值的最开始 可 ...