2025.05.26__Codeforces Round 1027 (Div. 3)(F)
F题题目链接

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分解成素数,然后就不知道怎么求最小次数了(日常卡住)
然后偷看师兄代码(诶嘿),原来是用记忆化搜索实现的。

浙公网安备 33010602011771号