2025.05.26__Codeforces Round 1027 (Div. 3)(F)

F题题目链接

image

F题大意

给定x、y、k,通过两种操作把x变成y,求最小操作次数。
操作1:把x乘上a倍(1<=a<=k)。
操作2:把x除以a倍,必须是整除(1<=a<=k)。

思路

这题很明显跟素数有关。
x、y可以拆成一堆素数的乘积,如果是x、y共有的部分素数则不用变,我们要把x多余的素数除掉,然后在乘上y多余的素数,这样x就变成了y。
然后就只剩下一个难题了,如何找到除掉x多余的素数和乘上y多余的素数的最小操作数(这两个操作其实是等效的)。
这里我们可以使用记忆化搜索,把一个数除成1的所有可能路径都跑一遍,记录最小次数。
为了防止超时,我们可以采用常见的map记录的方法,进行记忆化搜索。

点击查看代码
#include <bits/stdc++.h>
//#define int long long 
#define PII pair<int,int>
#define pb push_back
#define fi first
#define se second
#define endl '\n'
using namespace std;
const int N=1e6+10,M=1010,mod=1e9+7;
const int INF=0x3f3f3f3f;
const int inf=0x3f3f3f3f3f3f3f3f;
int n,m,k;
unordered_map<int,int> memo;

int get(int x){
	if(x==1) return 0;
	if(memo.count(x)) return memo[x];
	
	int minv=INF;
	for(int i=min(k,x);i>1;i--){
		if(x%i==0){
			int cnt=get(x/i);
			if(cnt!=-1) minv=min(minv,cnt+1);
		}
	}
	if(minv==INF) return memo[x]=-1;
	else return memo[x]=minv;
}
     
void solve(){
	memo.clear();
	int x,y;
    cin>>x>>y>>k;
    if(x==y) return void(cout<<0<<endl);
    int g=__gcd(x,y);
    x/=g,y/=g;
    int a=get(x),b=get(y);
    if(a==-1||b==-1) cout<<-1<<endl;
    else cout<<a+b<<endl;
}

signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int _=1;
    cin>>_;
	while(_--) solve();
	return 0; 
} 

做后总结

做这题的时候很快就想到了把x、y分解成素数,然后就不知道怎么求最小次数了(日常卡住
然后偷看师兄代码(诶嘿),原来是用记忆化搜索实现的。

posted @ 2025-05-27 21:09  _hu  阅读(49)  评论(0)    收藏  举报