B君和G君聊天的时候想到了如下的问题。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。
Input
包含至多10001组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 1018。
Output
对于每组数据输出一行,表示最大的位或。
Sample Input
5
1 10
0 1
1023 1024
233 322
1000000000000000000 1000000000000000000
Sample Output
15
1
2047
511
1000000000000000000

给一个区间求出x和y满足l<=x<=y<=r 然后使x|y值最大
这题要用二进制的思路来做,然后明确一点是我们无需把x和y具体算出来,虽然好像也能算的,但是我们只需要找出最后|出来的值最大是多少即可,而这个值我们用二进制来分析
首先将两个区间端点转化为二进制,如果位数不同,那必然是r的位数大于l的位数,比如
10000100
x x101011
那这样的话,这个异或的最大值一定是11111111,也就是l的位数全部都是1,为什么呢,因为或 | 就是两个数的对应数位有一个为1就是1,这样的话, r是1的位数我们就不用管,而r是0的位数,我们肯定能找到一个数比他小,就是 r-1,他对应r为0的数位他就刚好是1,或起来就是全1了,就是(2^len_R)-1
第二种情况是位数相等的,比如
11001010
10001000
这种情况从高位开始比较,直接找到不等的那一位,而前面相等的哪几位肯定不能该,(也就是区间[l,r]里面的任何x y的那几位都相等),然后从不同的哪一位开始,就可以取x y使得或起来全都是1,仔细想想确实是这样的,因为不同的那一位一定是r是1,l是0的,后面无论怎么取都能保证每一位能分配一个1

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll l,r;
ll b1[105],b2[105];
ll solve(ll l,ll r){
   
    if(l==r){
   
        return l;
    }
    ll lel=0,ril=0;
    memset(b1,0,sizeof(b1));
    memset(b2,0,sizeof(b2));
    ll x=l,res=0;
    while(x){
   
        b1[++lel]=x%2;
        x/=2;
    }
    x=r;
    while(x){
   
        b2[++ril]=x%2;
        x/=2;
    }
    if(lel!=ril){
   
        return (1ll<<ril)-1;
    }
    for(ll i=ril;i>0;i--){
   
        if(b1[i]==b2[i]){
   
            res+=b1[i]*(1ll<<(i-1));
        }
        else{
   
            res+=(1ll<<i)-1;
            return res;
        }
    }
}
int main(void){
   
    ll T;
    scanf("%lld",&T);
    while(T--){
   
        scanf("%lld%lld",&l,&r);
        printf("%lld\n",solve(l,r));
    }
    return 0;
}