F. Small Operations
F. Small Operations
Given an integer $x$ and an integer $k$. In one operation, you can perform one of two actions:
- choose an integer $1 \le a \le k$ and assign $x = x \cdot a$;
- choose an integer $1 \le a \le k$ and assign $x = \frac{x}{a}$, where the value of $\frac{x}{a}$ must be an integer.
Find the minimum number of operations required to make the number $x$ equal to $y$, or determine that it is impossible.
Input
The first line of the input contains one integer $t$ ($1 \le t \le 10^4$) — the number of test cases.
The only line of each test case contains three integers $x$, $y$ and $k$ ($1 \le x, y, k \le 10^6$).
It is guaranteed that the sum of $x$ and the sum of $y$ across all test cases does not exceed $10^8$.
Output
For each test case, output $-1$ if it is impossible to achieve $x=y$ using the given operations, and the minimum number of required operations otherwise.
Example
Input
8
4 6 3
4 5 3
4 6 2
10 45 3
780 23 42
11 270 23
1 982800 13
1 6 2
Output
2
-1
-1
3
3
3
6
-1
解题思路
令 $d = \gcd(x,y)$,有 $x = \frac{x}{d} \cdot d$,其中 $\frac{x}{d}$ 是 $y$ 中不存在的因子,需要通过操作 $2$ 从 $x$ 中除去。又因为 $y = \frac{y}{d} \cdot d$,还需要通过操作 $1$ 对除剩的 $d$ 乘上 $\frac{y}{d}$ 将其变成 $y$。显然两种操作是独立的,对于操作 $1$ 我们希望用最少的次数凑出 $\frac{y}{d}$。对于操作 $2$ 则希望用最少的次数凑出 $\frac{x}{d}$。
上面两种操作都可以归为一个问题:凑出某个值 $v$ 的最少次数是多少。赛时想到的做法是先将 $v$ 进行质因数分解 $v = p_1^{\alpha_1} p_2^{\alpha_2} \cdots p_k^{\alpha_k}$,由于 $\alpha_1 + \alpha_2 + \cdots + \alpha_k \leq \log{X} < 20$,因此很容易想到状压 dp。
定义 $f(s)$ 表示凑出二进制状态 $s$ 所表示的质因子的乘积的最少次数,根据最后一次操作凑出的乘积进行转移,即枚举 $s$ 的所有非空子集进行状态转移。有状态转移方程 $f(s) = \min\limits_{t \subseteq s \text{ and } f(t) \leq k}\left\{ f(t) \right\} + 1$,其中 $f(t)$ 是二进制状态 $t$ 表示的质因子的乘积。整个 dp 的复杂度是 $O\left(3^{\log{v}}\right)$,过不了。
可以发现,每次操作实际上是凑出 $v$ 的一个约数,包括上述 dp 每次转移的状态 $t$ 对应质因子的乘积也是 $v$ 的约数。所以我们能不能不考虑质因子的组合,而是每次通过一个约数进行转移?
重新定义 $f(i)$ 表示凑出值 $i$ 所需的最少次数,根据最后一次操作凑出的 $i$ 的约数进行转移,状态转移方程为 $f(i) = \min\limits_{d \leq k \mid i}\left\{ f\left(\frac{i}{d}\right) \right\} + 1$。这样时间复杂度就降到了 $O(v \log{v})$ 了。不过如果直接从 $1$ 到 $v$ 去枚举 $i$ 进行转移还是会超时,博主不知道为什么,麻烦知道的大佬在评论区留言 qwq。优化的方法也很简单,如果 $i \nmid v$ 显然状态 $f(i)$ 是不存在的,因为我们每次都凑出 $v$ 的约数,所以之前累乘的结果也是 $v$ 的约数。因此我们只需从小到大枚举 $i \mid v$ 的 $i$ 进行转移即可。
AC 代码如下,时间复杂度为 $O(X \log{X} + Y \log{Y})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 5, INF = 0x3f3f3f3f;
int x, y, k;
vector<int> ds[N];
int f[N];
void init() {
for (int i = 2; i < N; i++) {
for (int j = i; j < N; j += i) {
ds[j].push_back(i);
}
}
}
int get(int n) {
for (auto &i : ds[n]) {
f[i] = INF;
for (auto &j : ds[i]) {
if (j > k) break;
f[i] = min(f[i], f[i / j] + 1);
}
}
return f[n];
}
void solve() {
cin >> x >> y >> k;
int d = __gcd(x, y);
int ret = get(x / d) + get(y / d);
cout << (ret < INF ? ret : -1) << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
参考资料
Codeforces Round #1027 (Div. 3) Editorial:https://codeforces.com/blog/entry/143268
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18899422

浙公网安备 33010602011771号