【位运算】Strange Test—CF1632C

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;
}
posted @ 2023-09-18 21:03  AC_2656  阅读(34)  评论(0)    收藏  举报