J. Xingqiu‘s Joke

  • Post author:
  • Post category:其他



传送门




题意:

给你两个数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 版权协议,转载请附上原文出处链接和本声明。