【位运算】Strange Test—CF1632C
- 本题考查了思维、位运算、数学化简能力。
思路
下面大部分是cf官方题解的原话,因为我认为cf这个题的题解写得确实很好。
取或操作最多只能用一次,因为 $a|b \ge b$,所以在使用取或操作之后,我们只能使用第二个操作(自增 $b$)。
如果我们不使用取或操作,答案就是 $b - a$。
如果我们使用了取或操作。在此之前,我们使用了第一个和第二个操作若干次,令结果值 $a$ 和 $b$ 分别为 $a'$ 和 $b'$($a \leq a'$,$b \leq b'$)。在这种情况下,答案将是 $(a' - a) + (b' - b) + ((a' \ | \ b') - b') + 1 = a' + (a' \ | \ b') + (1 - a - b)$。由于 $(1 - a - b)$ 是常数,这等价于使 $a' + (a' \ | \ b')$ 最小。
为了实现这个目标,我们可以递增地枚举 $a'$ 从 $a$ 到 $b$ 的值。对于每一个 $a'$,我们需要使 $a' \ | \ b'$ 最小,而最佳的 $b'$ (首先满足 $b'\geb$,其次满足 $a' + (a' \ | \ b')$ 最小)可以按照以下方式构造:
将 $b'$ 设为零,并从高到低迭代位数。有四种情况:
- 如果当前位的 $a'$ 是 0,且 $b$ 是 1,则将 $b'$ 的当前位设为 1。
- 如果当前位的 $a'$ 是 0,且 $b$ 是 0,则将 $b'$ 的当前位设为 0。
- 如果当前位的 $a'$ 是 1,且 $b$ 是 1,则将 $b'$ 的当前位设为 1。
- 如果当前位的 $a'$ 是 1,且 $b$ 是 0,则将 $b'$ 的当前位设为 1,并停止。
这种构造 $b'$ 的方法并不好理解。需要想很长时间。我一开始本以为我已经理解了,但当我写这篇博客的时候发现我的理解其实是错误的,直到我写到这里才真正地理解。
$Code$
#include <bits/stdc++.h>
#define int long long
#define sz(a) ((int)a.size())
#define all(a) a.begin(), a.end()
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int a, b;
void solve() {
cin >> a >> b;
int res = b - a;
for (int a_ = a; a_ <= b - 1; a_ ++) {
int now_res = 1 - a - b + a_;
int b_ = b;
for (int i = 30; i >= 0; i --) {
if ((a_ >> i & 1) && !(b >> i & 1)) {
b_ = ((b >> i) + 1) << i;
break;
}
}
now_res += a_ | b_;
res = min(res, now_res);
}
cout << " ";
cout << res << "\n";
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T; cin.get();
while (T --) solve();
return 0;
}

浙公网安备 33010602011771号