官方题解
CashCollectFactory · · 题解
这一套 ICPC 的问题全是关于原神的诶,重云不可爱,但还是必须交一份题解来宠爱重云呢~
题目大意
给出两个正整数
题目分析
一眼看上去就是深度优先搜索吧?
总的来说,如果不进行除法操作,那么
如果只使用前两种操作,那么
因此记
但状态的第一维如果和除以因数的顺序有关,那状态数又超了。但无需担心,实际上对于整数
通过以下方式完成证明:
若
该式可通过数学归纳法证明。
上面两个式子可以看作长度为
由于以任意顺序进行全部上取整的整除得到的结果一定是最大的,进行全部下取整的整除得到的结果一定是最小的,那么上下整除混合得到的结果自然在两者中间。该性质得证。
代码实现
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
int n,a,b,t;
vector<int>v;
unordered_map<int,int>level;
int gethash(int b,int c) {//哈希
return b*1e9+c;
}
int DFS(int b,int c) {
if(b==1)return 0;
if(c==1)return b-1;//差值为1,只能一直减
if(level[gethash(b,c)])return level[gethash(b,c)];//记忆化搜索
int mn=b-1;//至少需要的次数
for(auto i:v)//遍历所有的质因子
if(c%i==0) {//如果还没有除过
int ans=b%i;//获得差距
mn=min({mn,ans+1+DFS(b/i,c/i),i-ans+1+DFS(b/i+1,c/i)});
//分别是b大于i的情况和b小于i的情况,+1是因为进行了一次除
}
return level[gethash(b,c)]=mn;
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cin >>t;
while(t--) {
cin >>a>>b;
if(a<b)swap(a,b);//强制b为小值
int c=a-b;
v.clear();
for(int i=2; i<=c/i; i++)
if(c%i==0) {//获得质因子
v.push_back(i);
while(c%i==0)c/=i;
}
if(c>1)v.push_back(c);//最后除剩的也是质因子
cout <<DFS(b,a-b)<<endl;//记忆化搜索
}
return 0;
}