隐藏
「fstqwq的2017/10/07模拟题」斐波那契 - 找规律 | Bill Yang's Blog

路终会有尽头,但视野总能看到更远的地方。

0%

「fstqwq的2017/10/07模拟题」斐波那契 - 找规律

题目大意





题目分析

话说$fstqwq$大佬出的题真的很负责任呢,虽然风格和NOIP不太像的说。

$fstqwq$给出的题解讲得比较详细了。
这棵斐波拉契数列构造的树很明显具有规律性。
不妨对父亲打个表。
$2\,3\,4\,5\,6\,7\,8\,9\,10\,11\,12\,13$
$1\,1\,1\,2\,1\,2\,3\,1\,\,\,2\,\,\,3\,\,\,\,4\,\,\,\,5$

发现父亲结点呈斐波拉契数列的规律分布。

因为斐波拉契第$60$项就已经超过范围了,故我们可以暴力爬树,每次选择编号更大的向上爬直到编号相等。

但是我们要更快的找到父亲结点。
不难发现结点$x$的父亲结点就是$x-f[i]$,其中$f[i]$是指在该编号前的最大斐波拉契项。

不难想到在斐波拉契数列中进行二分寻找父亲,暴力找似乎会被卡掉。

时间复杂度$O(m\times 30\times \log_260)$


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

typedef long long LL;

inline const LL Get_Int() {
LL num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}

LL t,f[65];

int main() {
t=Get_Int();
f[0]=f[1]=1;
for(int i=2; i<=60 ; i++) {
f[i]=f[i-1]+f[i-2];
if(f[i]>1000000000000)break;
}
while(t--) {
LL x=Get_Int(),y=Get_Int();
while(x!=y) {
LL tmp=max(x,y);
int Left=1,Right=60;
while(Left<=Right) {
int mid=(Left+Right)>>1;
if(tmp<=f[mid])Right=mid-1;
else Left=mid+1;
}
if(x>y)x-=f[Right];
else y-=f[Right];
}
printf("%lld\n",x);
}
return 0;
}

特别声明

本题解已获得$fstqwq$授权,原作者使用CC BY-NC-ND 4.0协议进行共享。
转载本套题请联系$fstqwq(QQ:849199382)$。

姥爷们赏瓶冰阔落吧~