- 题目传送门:~~~
题目大意
有 t 次查询,每次查询(l, r)区间中,二进制下 1 的个数出现最多的数,如果有多个答案,输出最小的那个
分析
我们只需要在 l 上补 1 就可以了。具体操作:
- step1:令结果res = l,再定义一个指针 ind = 1。
- step2:我们比较 res | ind 和 r 的关系,如果 (res | ind) <= r ,我们就更新 res = res | ind,| 运算可以把 ind 二进制下的 1 给加到 res 上。 如果 (res | ind) > r ,当前res就是答案
- step3:我们让 ind 右移一位,再回到 step2
我们拿一个样例看看
R = 1011 01012
L = 1010 00102
令 res = 1010 00102,ind = 0000 00012
- 第一次执行step2
(res | ind) = 1010 00112 < 1011 01012
更新 res = res = res | ind = 1011 00112
更新 ind = 0000 00102
- 第二次执行step2
(res | ind) = 1010 00112 < 1011 01012
更新 res = res = res | ind = 1011 00112
更新 ind = 0000 01002
- 第三次执行step2
(res | ind) = 1010 01112 < 1011 01012
更新 res = res = res | ind = 1010 01112
更新 ind = 0000 10002
- 第四次执行step2
(res | ind) = 1010 11112 < 1011 01012
更新 res = res = res | ind = 1011 11112
更新 ind = 0001 00002
- 第五次次执行step2
(res | ind) = 1011 11112 > 1011 01012
结束
通过上边的过程我们可以看出,在给 l 不断补 1 过程中,我找到了答案
这个题的解决方法有很多,最突出的问题就是解决输出最小的答案。我们通过右到左的扫描二进制下的 r 和 l 实现最小答案
代码
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main(){
int ncase;
cin >> ncase;
while(ncase--){
ll l, r;
cin >> l >> r;
for(ll i = 1; (l | i) <= r; i <<= 1) l |= i; // 补一的过程
cout << l << endl;
}
return 0;
}