D.最强单身狗

华中师范大学 2016 年“计蒜客杯”第十四届程序设计竞赛

D. 最强单身狗
Description
有若干只单身狗排成一排,编号从 l 到 r。GBX 发现,一个单身狗的编号的二进制中 1 的数量越多,表示该单身狗越强(就是单身越久咯 - _ -|||) 。 GBX想找到一只最强的单身狗和他做朋友(强者惺惺相惜吧 >_<)。

Input
输入一个 T(T ≤ 1000)表示 T 组数据。
对于每组数据输入两个正整数 l,r(1 ≤ l ≤ r ≤ 1e18),表示单身狗的标号。

Output
对于每组数据输出一个数表示最强的单身狗的标号(如果有多个输出最小的那个),每组数据占一行。

Sample Input
2
1 100
123 654

Sample Output
63 511

分析:
相同位数,全1的数最好,将这些数打表放到数组b[70]中
情况一:存在b[i] (l<=b[i]<=r),那么找到最大的b[i]即可
情况二:不存在b[i] (l<=b[i]<=r),那么l和r一定位数相同,且最高位相同,那么可以l和r最高位一起去掉,l和r位数减小,重复上面步骤。

注意:将l和r的位数保存下来,每次将位数减一而不是计算新的l和r的位数!(下面代码中被注释掉的部分就是错误的地方)
比如当l=1001b,r=1011b,正确答案是1011b

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long

LL b[70];

void init(){
    LL t=1;
    for(int i=1;i<=60;i++){
        t<<=1;
        b[i]=t-1;
    }
}

int length(LL x){
    int sum=0;
    while(x){
        x>>=1;
        sum++;
    }
    return sum;
}

LL has(LL l,LL r){
    for(int i=60;i>=1&&b[i]>=l;i--){
        if(b[i]<=r){
            return b[i];
        }
    }
    return -1;
}
LL l,r;

int main(){
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld",&l,&r);
        if(l==r){
            printf("%lld\n",l);
            continue;
        }
        LL ans=0;
        int cnt=max(length(l),length(r));
        while(1){
            LL getb=has(l,r);
            if(getb!=-1){
                ans<<=cnt;
                ans+=getb;
                printf("%lld\n",ans);
                break;
            }
//            int num=length(r);
//            LL tmp=(1LL<<(num-1))-1;
            cnt--;
            LL tmp=(1LL<1;
            ans<<=1;
//            ans+=r>>(num-1);
            ans+=r>>cnt;
            l&=tmp;
            r&=tmp;
        }
    }
    return 0;
}

你可能感兴趣的:(题解)