Luogu P10869 LCMs 题解 [ 黄 ] [ lcm ] [ 最短路 ]

LCMs:很好的数论和构造题。

显然我们不可以直接建图跑最短路。

于是考虑分讨。

倍数关系

答案显然为 max(a,b)

相等关系

答案显然为 0

gcd(a,b)>1

我们可以先走到 gcd(a,b) 处,再到达 b,答案为 a+b

gcd(a,b)=1

直接分讨不太好做,我们考虑用一点时间换取代码的简洁。

可以发现,我们中间会用到的点只有 3 个:minpa,minpb,2,其中 minpx 表示数 x 的最小质因数。

为什么要用最小的?因为既然 a,b 已经互质,所以无论如何转化到哪一步它都是互质的,我们就要尽可能减小这一步中转的代价。这就是 minp 的由来。

那么我们化为最小质因子后,就直接是两个数的积了吗?并不是,我们还可以发现这一个构造:minpa2minpb。可以让这一步的代价变为 minpa×2+minpb×2。并且其他数显然做这个中转点不优,因为 a,b 已经是最小质因子了。

于是选这 5 个点出来,跑 Floyd 即可。要是愿意写,写单源最短路也可以。

时间 O(tn)

代码

/*
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;
}
posted @   KS_Fszha  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示