Luogu P10869 LCMs 題解 [ 黃 ] [ lcm ] [ 最短路 ]

KS_Fszha發表於2024-11-16

LCMs:很好的數論和構造題。

顯然我們不可以直接建圖跑最短路。

於是考慮分討。

倍數關係

答案顯然為 \(\max(a,b)\)

相等關係

答案顯然為 \(0\)

\(\gcd(a,b)>1\)

我們可以先走到 \(\gcd(a,b)\) 處,再到達 \(b\),答案為 \(a+b\)

\(\gcd(a,b)=1\)

直接分討不太好做,我們考慮用一點時間換取程式碼的簡潔。

可以發現,我們中間會用到的點只有 \(3\) 個:\(minp_a,minp_b,2\),其中 \(minp_x\) 表示數 \(x\) 的最小質因數。

為什麼要用最小的?因為既然 \(a,b\) 已經互質,所以無論如何轉化到哪一步它都是互質的,我們就要儘可能減小這一步中轉的代價。這就是 \(minp\) 的由來。

那麼我們化為最小質因子後,就直接是兩個數的積了嗎?並不是,我們還可以發現這一個構造:\(minp_a \to 2 \to minp_b\)。可以讓這一步的代價變為 \(minp_a\times 2+minp_b \times 2\)。並且其他數顯然做這個中轉點不優,因為 \(a,b\) 已經是最小質因子了。

於是選這 \(5\) 個點出來,跑 Floyd 即可。要是願意寫,寫單源最短路也可以。

時間 \(O(t \sqrt {n})\)

程式碼

/*
1. 倍數關係,ans=max(a,b);
2. 相等關係,ans=0;
3. 互質關係,找出 a,b,minp_a,minp_b,2 這 5 個點跑最短路,因為要使分別的質因數最小(中轉的代價最小),顯然選其他質因數必定不優
4. 有公因數關係:走到 gcd 處,答案為 a+b;
時間 O(sqrt(n)t)
*/

#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pi;
int t;
ll d[10][10];
vector<int>g;
ll gcd(ll a,ll b)
{
    if(b==0)return a;
    return gcd(b,a%b);
}
ll lcm(ll a,ll b)
{
    return b/gcd(a,b)*a;
}
void floyd()
{
    for(int i=0;i<g.size();i++)
    {
        for(int j=0;j<g.size();j++)
        {
            d[i][j]=lcm(g[i],g[j]);
            if(i==j)d[i][j]=0;
        }
    }
    for(int k=0;k<g.size();k++)
    {
        for(int i=0;i<g.size();i++)
        {
            for(int j=0;j<g.size();j++)
            {
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
            }
        }
    }

}
void solve()
{
    ll a,b;
    cin>>a>>b;
    if(a>b)swap(a,b);
    if(a==b)cout<<0<<'\n';
    else if(b%a==0)cout<<b<<'\n';
    else if(gcd(a,b)>1)cout<<a+b<<'\n';
    else
    {
        int minp_a=1,na=a;
        for(int i=2;i<=a/i;i++)
        {
            if(na%i==0)
            {
                minp_a=i;
                break;
            }
        }
        if(minp_a==1)minp_a=a;
        int minp_b=1,nb=b;
        for(int i=2;i<=b/i;i++)
        {
            if(nb%i==0)
            {
                minp_b=i;
                break;
            }
        }
        if(minp_b==1)minp_b=b;
        g.clear();
        g.push_back(a);
        g.push_back(b);
        g.push_back(minp_a);
        g.push_back(minp_b);
        g.push_back(2);    
        floyd();
        cout<<d[0][1]<<'\n';    
    }
}

int main()
{
    //freopen("sample.in","r",stdin);
    //freopen("sample.out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>t;
    while(t--)solve();
    return 0;
}

相關文章