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;
}
posted @ 2024-08-17 06:45  underthetime  阅读(2)  评论(0编辑  收藏  举报