【补题】The 2021 ICPC Asia Nanjing Regional Contest Problem J. Xingqiu’s Joke
题意:多组样例T,给x,y,三个操作1.x+1,y+1 2.x-1,y-1 3.x/p,y/p,p是x,y的共素数,让x或y等于1问操作次数最少。
思路:
1.很简单想到的,为了把一个数变成1,要么减,要么除法,加法说白了也是为了除法。
2.x和y的除法不一定能直接求出,15和7不行16和8就可以了,看不出来怎么判断?分解d=(x-y),因为a+k,b+k的gcd肯定是d的某一个质因数(题目也这么要求的)
因为能有素数除一定满足a=kb,所以a-b=(k-1)*p一定是有关联的。
3.考虑对于当前剩下的x,y的除法选择其中一个质因数(其实就是爆搜,枚举能除的),但是很显然超时,但是枚举的时候可能会出现 先除3再除7 和 先除7再除3,所以其实是重复的……加入记忆化搜索,可能大大减少,本来是30^30,变成了类似组合数的时间复杂度(如果有错误欢迎指正)
那么就此解决了,本题关键记忆化搜索,也就是点3,利用记忆化,将本来其实只是改变除法顺序重复的搜索大大减少,时间一来就足够了。
参考了:J. Xingqiu‘s Joke(2021ICPC-南京)(记忆化搜索 + 数论)_[icpc2021 nanjing r] xingqiu's joke-CSDN博客
代码是vp的时候改来的,所有有些地方是繁琐不必要的,如果看不惯请移步原文。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
#define pii pair<int, int>
#define lowbit(x) (x & (-x))std::map<std::pair<int,int>,int> mp;int dfs(int x, int y, std::set<int> &se)
{if(mp.count({x,y})){return mp[{x,y}];}int ans=y-1;if(y==1){mp[{x,y}]=ans;return ans;}mp[{x,y}]=(y-1);for (auto i : se){int now=y-1;if((x-y)%i!=0) continue;int up = i - (y % i);if (up == i)up = 0;int down = y % i;if (1){int xx = x + up, yy = y + up;xx = xx / i;yy = yy / i;now=1+up+dfs(xx, yy, se);// std::cout << x << " 12 " << y << " " << now << '\n';mp[{x,y}]=std::min(now,mp[{x,y}]);}if (1){int xx = x - down, yy = y - down;xx = xx / i;yy = yy / i;now=1+down+dfs(xx, yy, se);// std::cout << x << " 23 " << y << " " << now << '\n';mp[{x,y}]=std::min(now,mp[{x,y}]);// std::cout << x << " 234 " << y << " " << mp[{x,y}] << '\n';}}return mp[{x,y}];}void solve()
{mp.clear();int x, y;std::cin >> x >> y;if (x < y)swap(x, y);int d = x - y;int now = d;std::set<int> zs;for (int i = 2; i <= sqrt(now); i++){if (now % i == 0){while (now % i == 0){now = now / i;}zs.insert(i);}}if (now != 1)zs.insert(now);dfs(x, y, zs);std::cout << mp[{x,y}] << '\n';// for(auto i : mp){// std::cout << i.first.first << " " << i.first.second << " " << i.second << '\n';// }
}signed main()
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);int t = 1;cin >> t;while (t--)solve();}