当我看到数据范围的那一刻,\(10^9\)给我吓死了。
Solution
看到数据范围千万不要慌,先考虑直接建树,可是\(10^9\)不给你MLE就算好的了,于是考虑走一步看一步。
既然是两个节点的距离,那么就可以一直然当前大的节点先跳到父节点,同时让次数加一,直到节点相同再返回次数。
看到这儿你会发现,这题就是一个经典的LCA问题。怪不得我看标签有LCA
那么父节点怎么求呢???
实际聪明的你一定会发现,一个数的最大因数 = 这个数 / 这个数的最小因数,那么即可遍历 2 ~ n,一直找到这个数的最小因数,找到就返回 \(n / i\)。
代码
#include<bits/stdc++.h>
using namespace std;
int f(int a){
for(int i = 2; i <= a; i++)
if(a % i == 0) return a / i;
}
int lca(int a, int b){
int k = 0;
while(a != b){
if(a > b) a = f(a);
else if(a < b) b = f(b);
k++;
}
return k;
}
int main(){
int q;
cin >> q;
while(q--){
int x, y;
cin >> x >> y;
cout << lca(x, y) << endl;
}
}
但是交上去你就会发现,只能喜提 \(60pts\) 的高分,那怎么优化呢?
优化
你会发现,过了 \(\sqrt{n}\) 的时候,就重复了,于是我们就只用遍历到 \(\sqrt{n}\) 就行了。
记得别忘了找不到就返回0!!!
根号就这样,凑合着看吧。
AC代码
#include<bits/stdc++.h>
using namespace std;
int f(int a){
for(int i = 2; i <= sqrt(a); i++){
if(a % i == 0) return a / i;
}
return 1;
}
int lca(int a, int b){
int k = 0;
while(a != b){
if(a > b) a = f(a);
else if(a < b) b = f(b);
k++;
}
return k;
}
int main(){
int q;
cin >> q;
while(q--){
int x, y;
cin >> x >> y;
cout << lca(x, y) << endl;
}
}
完结撒花 \ ^ _ ^ /