CF2114F 8.29考试T1

Codeforces CF2114F

洛谷链接:https://www.luogu.com.cn/problem/CF2114F

题目简述

给你两个正整数 \(x,k\)。进行以下两种变换之一称为一次操作:

  • 选择一个满足 \(1 \le a \le k\) 的正整数 \(a\),使 \(x\) 变为 \(x\cdot a\)
  • 选择一个满足 \(1 \le a \le k\) 的正整数 \(a\),使 \(x\) 变为 \(\frac{x}{a}\),要求操作完后 \(x\) 值是整数。
    你需要找出使 \(x\) 变为给定正整数 \(y\) 的最小操作次数,或判断无解。

解法

因为是通过乘除来把x变为y,容易想到:x和y中因子相同的部分是不需要进行变换的,所以我们可以先将x和y都除以两者的最大公因数;
由于除完之后x和y是互质的,那么可以发现此时要将x变换成y是一定会经过1的;
换句话说,此时将x变成y的过程,是先将x除以一些数变为1,再把1乘上一些数变成y;
很明显这个过程是可逆的,于是问题就变成了1到x的步数加上1到y的步数;
这样我们就成功把乘除变化的问题变成了两个递推求最优解的问题,分别dfs即可;
代码:

#include<bits/stdc++.h>
using namespace std;
int t,x,y,k,dp[1000005];
bool panduanwujie(int x){//判断除以gcd之后的x和y中有没有大于k的因子,如果有那么就判断无解
	for(int i=2;i*i<=x&&i<=k;i++){//枚举因子
		while(x%i==0){
			x/=i;
		}
	}
	if(x>k) return 0;
	else return 1;
}
int gcd(int a,int b){
	int r=a%b;
	if(r==0) return b;
	return gcd(b,r);
}
int dfs(int x){
	if(x==1) return 0;//如果目标本来就是1,那么就特判需要0步
	if(dp[x]!=0) return dp[x]; //记忆化搜索
	if(x<=k) return dp[x]=1;//剪枝:如果目标小于k,那么显然一步就能完成
	dp[x]=1e9;
	for(int i=k;i>=1;i--){
		if(x%i==0){
			dp[x]=min(dp[x],dfs(x/i)+1);
		}
	}
	return dp[x];
}
int main(){
	cin>>t;
	for(int i=1;i<=t;i++){
		int d,ans=0;
		memset(dp,0,sizeof(dp));
		cin>>x>>y>>k;
		d=gcd(x,y);
		x=x/d; y=y/d;
		if(!panduanwujie(x)||!panduanwujie(y)){//判断无解
			cout<<"-1"<<endl;
			continue;
		}
		ans=dfs(x)+dfs(y);
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2025-08-29 21:19  Turkey_VII  阅读(12)  评论(0)    收藏  举报