ABC254Ex Multiply or Divide by 2 题解
题意
给定两个大小均为 \(n\) 的数组 \(A\) 和 \(B\),有两种操作: \(x\leftarrow \lfloor\dfrac{x}{2}\rfloor\) 和 \(x\leftarrow x\times 2\),求对 \(A\) 进行这两种操作,使 \(A\) 和 \(B\) 数组中相同元素出现次数相同的最少操作次数,若无解则输出 \(-1\)。
解题思路
可以发现,对于将 \(A\) 数组中的 \(A_i\) 进行操作一,等价于将 \(B\) 数组中的 \(B_j\) 进行操作二,前提是 \(B_j\) 为偶数。其中 \(1\le i,j\le n\)。
于是我们便可以把对于 \(A\) 数组执行的操作一转化为对于 \(B\) 数组的操作二。
所以我们使用贪心算法。考虑两个数组的最大值 \(a\) 与 \(b\) 的贪心策略:
- 若 \(a=b\),则可以直接消去;
- 若 \(a<b\),说明 \(b\) 大于 \(A\) 中的所有元素,则对 \(b\) 执行操作二,因为对 \(B\) 数组执行的操作二由操作一转化而来,一个整数乘以 \(2\) 总是会变成偶数,如果 \(b\) 为奇数则无解;
- 若 \(a>b\),说明 \(a\) 大于 \(B\) 中的所有元素,则对 \(a\) 执行操作二。
这个过程可以用优先队列进行维护。每个数至多只会操作 \(\log V\) 遍,时间复杂度 \(O(n\log n\log V)\),其中 \(V\) 为 \(A\) 和 \(B\) 数组中的最大值。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n,ans;
priority_queue<int> A,B; // 分别维护a与b数组的最大值
int main() {
scanf("%d",&n);
for (int i = 1,x;i <= n;i ++) {
scanf("%d",&x);
A.push(x);
}
for (int i = 1,x;i <= n;i ++) {
scanf("%d",&x);
B.push(x);
}
while (n > 0) {
int a = A.top(), b = B.top();
A.pop(); B.pop(); // 拿到当前A与B的最大值
if (a == b) continue; // 情况一
ans ++; // 累计答案
if (a < b) { // 情况二
if (b & 1) { printf("-1"); return 0; } // 判断b为奇数时的无解
A.push(a); B.push(b / 2); // 对b进行操作二
}
if (a > b) { // 情况三
A.push(a / 2); // 对a进行操作二
B.push(b);
}
}
printf("%d",ans);
return 0;
}
- 测评信息:R126761219 记录详情