J. Xingqiu‘s Joke

34 篇文章 1 订阅

传送门

题意:

给你两个数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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值