D. Equalization
题目大意
- 输入两个正整数 \(x\), \(y\)
- 每次选择一个不同的 \(k\) ,然后将 \(x\) 或 \(y\) 除以 \(2^k\), 同时代价为 \(2^k\)
- 计算使 \(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;
}