[ABC254Ex] Multiply or Divide by 2 题解

题意

给定两个大小均为 n n n 的数组 A A A B B B,有两种操作: x ← ⌊ x 2 ⌋ x\leftarrow \lfloor\dfrac{x}{2}\rfloor x2x x ← x × 2 x\leftarrow x\times 2 xx×2,求对 A A A 进行这两种操作,使 A A A B B B 数组中相同元素出现次数相同的最少操作次数,若无解则输出 − 1 -1 1

解题思路

可以发现,对于将 A A A 数组中的 A i A_i Ai 进行操作一,等价于将 B B B 数组中的 B j B_j Bj 进行操作二,前提是 B j B_j Bj 为偶数。其中 1 ≤ i , j ≤ n 1\le i,j\le n 1i,jn

于是我们便可以把对于 A A A 数组执行的操作一转化为对于 B B B 数组的操作二。

所以我们使用贪心算法。考虑两个数组的最大值 a a a b b b 的贪心策略:

  • a = b a=b a=b,则可以直接消去;
  • a < b a<b a<b,说明 b b b 大于 A A A 中的所有元素,则对 b b b 执行操作二,因为对 B B B 数组执行的操作二由操作一转化而来,一个整数乘以 2 2 2 总是会变成偶数,如果 b b b 为奇数则无解
  • a > b a>b a>b,说明 a a a 大于 B B B 中的所有元素,则对 a a a 执行操作二。

这个过程可以用优先队列进行维护。每个数至多只会操作 log ⁡ V \log V logV 遍,时间复杂度 O ( n log ⁡ n log ⁡ V ) O(n\log n\log V) O(nlognlogV),其中 V V V A A A B B 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;
}
  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值