题意:
给你两个数a,b,每次可对两个数同时进行三种操作:加1,减1或者同时除以他们的公共质因数,问使得其中任意一个数到达1的最小操作 次数。
思路:
不妨设a>b,f(a,d)表示a,b-a这组数转化为1的最小次数,d为b-a的值,设k为b-a的质因数,那么f(a,b)是可以由状态f(a/k,b/k)和f(a/k+1,b/k)转化而来,于是,通过dfs的方式求解。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll pri[100100];
int vis[100100];
unordered_map<ll,ll>f;
ll change(ll a,ll b)
{
return a*1e9+b;
}
int cnt;
void oula()
{
for(int i = 2; i <= 100000; i++)
{
if(!vis[i])pri[++cnt] = i;
for(int j = 1; j <= cnt && pri[j]*i <= 100000; j++)
vis[i*pri[j]] = 1;
}
}
int dpri[100100];
int cot;
int dfs(ll a,ll d)
{
// cout<<a<<" "<<d<<"\n";
if(a == 1)return 0;
else if(f[change(a,d)])return f[change(a,d)];
if(d == 1)return a-1;
ll now = a-1;
for(int i = 1; i <= cot; i++)
{
if(d%dpri[i] == 0)
now = min(now,1+min(dfs(a/dpri[i]+1,d/dpri[i])+dpri[i]-a%dpri[i], dfs(a/dpri[i], d/dpri[i])+a%dpri[i]));
}
return f[change(a,d)]=now;
}
int main()
{
oula();
int t;
cin>>t;
while(t--)
{
ll a,b;
cin>>a>>b;
cot = 0;
if(a > b)swap(a,b);
ll d = b-a;
for(int i = 1; i <= cnt && pri[i] <= d; i++)
{
if(d%pri[i] == 0)dpri[++cot] = pri[i];
while(d%pri[i] == 0)
{
d/=pri[i];
}
}
if(d>1)dpri[++cot] = d;
cout<<dfs(a,b-a)<<endl;
}
}
版权声明:本文为p15008340649原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。