洛谷mNOIP模拟赛Day1-斐波那契

题目背景

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

题目描述

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

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

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

洛谷mNOIP模拟赛Day1-斐波那契

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

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制
5
1 1
2 3
5 7
7 13
4 12
输出样例#1: 复制
1
1
2
2
4

说明

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

洛谷mNOIP模拟赛Day1-斐波那契

洛谷mNOIP模拟赛Day1-斐波那契


首先考虑70%的数据,

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

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

再考虑100%的数据,

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

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

于是有思路:二分s数组,使得s[i]+1<=a<=s[i]+f[i+1],这时候a的父亲就是a-s[i]

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

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

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

洛谷mNOIP模拟赛Day1-斐波那契

 #include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define ll long long
#define MAXN 1000005
#define LOG 21
using namespace std;
ll read(){
ll x=,f=;char ch=getchar();
while(ch<''||ch>''){if('-'==ch)f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
int fa[LOG][MAXN];
ll M=;
ll dep[MAXN];
ll f[MAXN]={,,};
ll s[MAXN]={,,};
vector<ll> v[];
int lca(int x,int y){
if(dep[x]<dep[y]){
swap(x,y);
}
for(int k=dep[x]-dep[y],p=;k;p++,k>>=){
if(k&){
x=fa[p][x];
}
}
if(x==y){
return x;
}
for(int k=LOG-;k>=;k--){
if(fa[k][x]!=fa[k][y]){
x=fa[k][x],y=fa[k][y];
}
}
return fa[][x];
}
void work(ll a,int t){
ll x=a;
v[t].push_back(x);
while(){
if(x<MAXN){
break;
}
int L=,R=;
while(R-L>){
int mid=(L+R)/;
if(s[mid]<x){
L=mid;
}
else{
R=mid;
}
}
if(s[R]<x){
x=x-s[R];
}
else{
x=x-s[L];
}
v[t].push_back(x);
}
}
void init(){
fa[][]=fa[][]=;
dep[]=dep[]=;
int i=,j=;
while(){
f[i]=f[i-]+f[i-];
s[i]=s[i-]+f[i];
if(s[i]>M){
break;
}
i++;
}
i=;
while(){
for(j=s[i-]+;j<=s[i]&&j<MAXN;j++){
fa[][j]=j-s[i-];
dep[j]=dep[j-s[i-]]+;
}
if(j>=MAXN){
break;
}
i++;
}
for(int k=;k<LOG;k++){
for(int i=;i<MAXN;i++){
fa[k][i]=fa[k-][fa[k-][i]];
}
}
}
void solve(){
int T=read();
while(T--){
ll a=read(),b=read();
if(a==b){
printf("%lld\n",a);
continue;
}
if(a<MAXN&&b<MAXN){
printf("%d\n",lca(a,b));
}
else{
v[].clear(),v[].clear();
work(a,);
work(b,);
int i=,j=,ok=;
while(i<v[].size()&&j<v[].size()){
if(v[][i]==v[][j]){
printf("%lld\n",v[][j]);
ok=;break;
}
if(v[][i]>v[][j]){
i++;
}
else{
j++;
}
}
if(!ok){
a=v[][v[].size()-],b=v[][v[].size()-];
printf("%d\n",lca(a,b));
}
}
}
}
int main()
{
// freopen("data.in","r",stdin);
init();
solve();
return ;
}
上一篇:Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRIDE environment variable to “*****”


下一篇:Ubuntu 18 + Redis安装