思路:所求数x满足,设l和r的二进制表示为:
,且l的长度小于等于r。
则l和r不等的情况下,设,则小于i的位可以全部取1,大于i的位与l和r相同:
。
第i位处理如下:第i位取0一定满足,所以考虑取1的情况,若取1时满足条件,则可取1(此时
,但不需要特别讨论);若取1时超过了r,则取0。
代码如下:
#include <cstdio>
using namespace std;
int l_digit[181], r_digit[181];
long long factor[181], sum[181];
int main(){
int n;
long long l, r, ans;
scanf("%d", &n);
factor[1] = 1, sum[1] = 1;
for(int i = 2; i < 181; i ++)
factor[i] = factor[i - 1] * 2, sum[i] = sum[i - 1] + factor[i];
for(int i = 0; i < n; i ++){
scanf("%I64d %I64d", &l, &r);
long long t1 = l, t2 = r;
int l_len = 0, r_len = 0;
if(r == l){
printf("%I64d\n", r);
continue;
}
while(t2){
r_digit[++r_len] = t2 & 1;
t2 >>= 1;
}
if(r == sum[r_len]){ //r全部位都为1,则r即是解
printf("%I64d\n", r);
continue;
}
while(t1){
l_digit[++l_len] = t1 & 1;
t1 >>= 1;
}
if(r_len > l_len){ //r至少有一位为0,则首位取0时x最小
ans = sum[r_len - 1];
}
else{
int point;
for(int j = r_len; j >= 1; j --){
if(!(r_digit[j] == l_digit[j])){
point = j;
break;
}
}
ans = sum[point - 1];
for(int j = point + 1; j <= r_len; j ++)
if(r_digit[j])
ans += factor[j];
if(ans + factor[point] <= r)
ans += factor[point];
}
printf("%I64d\n", ans);
}
return 0;
}