D. Equalization

题目大意

  1. 输入两个正整数 \(x\), \(y\)
  2. 每次选择一个不同的 \(k\) ,然后将 \(x\)\(y\) 除以 \(2^k\), 同时代价为 \(2^k\)
  3. 计算使 \(x = y\) 的最小代价

思路

每个 \(k\) 只能选择一次, 还有相应代价, 考虑背包dp

状态设计

\(x\ y\) 视为两个背包容积, \(f_{i, j, k}\) 表示前 \(i\) 个数, 把 \(x\) 变为 \(i\), \(y\) 变为 \(j\) 的最小代价

f[i][j][k] = f[i - 1][j][k];
if(j >= i) f[i][j][k] = min(f[i][j][k],f[i - 1][j - i][k] + (1LL << i));
if(k >= i) f[i][j][k] = min(f[i][j][k],f[i - 1][j][k - i] + (1LL << i));

最后再压缩一维, 答案代码

#include<bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 61;
LL x, y, t;
LL f[N][N];

void init()
{
    memset(f, 0x3f, sizeof f);
    f[0][0] = 0;
    for(int i = 1; i < 60; i++)
    {
        for(int j = 59; j >= 0; j--)
        {
            for(int k = 59; k >= 0; k--)
            {
                if(j >= i) f[j][k] = min(f[j][k],f[j - i][k] + (1LL << i));
                if(k >= i) f[j][k] = min(f[j][k],f[j][k - i] + (1LL << i));
            }
        }
    }
}
void solve()
{
    cin >> x >> y;
    LL ans = 1e18;
    for(int i = 0; i < 60; i++)
    {
        for(int j = 0; j < 60; j++)
        {
            if((x >> i) == (y >> j))
                ans = min(f[i][j], ans);
        }
    }
    cout << ans << '\n';
}

int main()
{
    ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
    init();
    cin >> t;
    while(t--)
        solve();
    return 0;
}
posted on 2025-04-28 14:37  LHWYAN  阅读(7)  评论(0)    收藏  举报