洛谷P13016 [GESP202506 六级] 最大因数

当我看到数据范围的那一刻,\(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;
    }
}

完结撒花 \ ^ _ ^ /