题意:
,每组测试数据输入两相异整数a,b (1≤a,b≤1e9),每次进行如下三种操作之一,直至a,b中至少有一个为1,输出最小步数
①两数同时加一
②两数同时减一
③两数同除以它们的一个公共质因子
这题有一个很重要的信息
再1操作和2操作中,a-b是不会变的
而假设3操作中a,b同时除以g,那么a和b的差值也会除以g
也就是如果我们设
,每一次除g,相当于
当然,g必须是c的质因子
显然如果我们设
,上式可以简化为
也就是我们要通过1,2,3操作,使得a变成1,而c会限制操作3
可以考虑将c分解质因数,通过分解出的质因数和12操作一起记忆化搜索
小优化:unorderedmap在多查询时会比map快很多,但如果想传入一个pair,需要自己写一个hash函数
代码如下:
#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et cout<<'\n'
#define xx first
#define yy second
using namespace std;
template <typename _Tp>void input(_Tp &x){
char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
struct hash_pair{
template <class T1, class T2>
size_t operator()(const pair<T1, T2>& p) const
{
auto hash1=hash<T1>{}(p.first);
auto hash2=hash<T2>{}(p.second);
return hash1^hash2;
}
};
vector<int> this_prime;
unordered_map<pll,int,hash_pair> mp;
signed main(){
function<void(int)> get=[&](int d){
for(int i=2;i*i<=d;++i){
if(d%i==0){
this_prime.pb(i);
while(d%i==0) d/=i;
}
}
if(d>1) this_prime.pb(d);
};
function<int(int,int)> dfs=[&](int a,int d){
pll now={a,d};
if(a==1){
return 0ll;
}
else if(mp[now]){
return mp[now];
}
int res=a-1;
for(auto v:this_prime){
if(d%v==0){
int x=dfs(a/v,d/v)+a%v;
int y=dfs(a/v+1,d/v)+v-a%v;
res=min({res,1+x,1+y});
}
}
mp[now]=res;
return res;
};
int T;
cin>>T;
while(T--){
int a,b;
input(a,b);
mp.clear();
this_prime.clear();
if(a>b) swap(a,b);
if(a==1){
cout<<0<<'\n';
continue;
}
else if(b-a==1){
cout<<a-1<<'\n';
continue;
}
else if(a==b){
cout<<1<<'\n';
continue;
}
get(b-a);
cout<<dfs(a,b-a)<<'\n';
}
}