题目大意



题目分析
话说$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)$。