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;
}