题目意思就是找一棵按上面链接所示的树对应的上面的两个点的最小公共祖先(LCP,Least Common Father),按照比较大小来依次返回自己的父亲节点就行了。具体看代码:getfather(a)函数是找父亲的代码
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxDepth = 21; long long three[maxDepth] , sum[maxDepth]; void init() { three[0] = 1; sum[0] = 0; for(int i=1;i<maxDepth;i++) { three[i] = three[i-1] * 3 ; sum[i] = sum[i-1] + three[i]; } for(int i = 0; i < maxDepth; i ++) { cout << three[i] << "\t"; } cout << endl; for(int i = 0; i < maxDepth; i ++) { cout << sum[i] << "\t"; } cout << endl; //cout << "INT_MAX\t" << INT_MAX <<endl; } int getfather(long long a) { if(a <= 3) return 0; int i; for(i=0;sum[i]<a;i++) ; i-- ; int tmp = (2+a-sum[i]) /3; int father = sum[i] - tmp + 1; return father; } int LCP(int a,int b) { while(a != b) { if(a > b) a = getfather(a); else b = getfather(b); } return a; } int main() { int a , b; init(); while(scanf("%d%d" , &a,&b) != EOF) { //cnt = 0; int ans = LCP(a , b); printf("%d\n" , ans); } return 0; }
其中 three array 保存3的指数
sum arry 保存截止到某一行为止,保存的数目-1,因为index是从0开始。
可以看见,sum[20] > INT_MAX 了,所以,sum中只要21个元素就能覆盖所有的 0 到 INT_MAX
同时,由于three[20]和sum[20] > INT_MAX,所以用long long 来保存。
three array: 1 3 9 27 81 243 729 2187 6561 19683 59049 177147 531441 1594323 4782969 1434890743046721 129140163 387420489 1162261467 3486784401 sum array: 0 3 12 39 120 363 1092 3279 9840 29523 88572 265719 797160 2391483 7174452 2152335964570080 193710243 581130732 1743392199 5230176600 INT_MAX 214748364
最后,交替计算当前节点的父节点,知道两者的父节点相同为止。
getFather 的计算也比较简单,和sum array 比较,找到sum[i] > node, 然后i--,知道,节点处于行的上一行。
然后计算offerset=(node-sum[i]+2)/3 就是其距离sum[i]的偏移量,所以father= sum[i]-offerset + 1;
举例:如要查找17的father,查找到 12 < 17 < 39, 所以17 处于sum[2]= 12 的下一行。
offset = (17+2 - 12) /3 = 2, 也就是说 17 的father 距离 sum[2]有两个距离。实际上是一个,
所以father = sum[2]-offset + 1 = 12 -2 + 1 = 11.
时间: 2024-10-13 01:42:36