杭电 5969 最大的位或

题目链接:点我
Problem Description
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

其实有时做题还是要看一些基础知识的吧,比如这题如果对二进制转换很清楚的话,一下就可以看到问题的本质了,感觉思维和基础还是有一些相辅相成的(蒟蒻见解)求大佬不要见笑

把左边界和右边界化成二进制,然后直接从小到大遍历,不同的话后面就直接全部补1了,然后肯定会有人要反驳了,为什么要全部补1,比如1000,另一个数比这个数小,但是一定会遍历到0111,然后这不是全部补1了吗,哈哈哈,那么还有一中情况呢?就是,举个栗子,1011和1001,这个你怎么弄呢?恩就是如果相同且为1的话就在这个位置加上1啊,这里就是加上1000(这里是二进制)
虽然卖萌可耻,但是我目前没有找到其他的方法来娱乐身心。这就是人生啊,苦逼啊

#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
typedef long long ll;
using namespace std;
int bin1[1000];
int bin2[1000];
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll a,b;
        int i=0,j=0;
        ll ans=0;
        scanf("%lld %lld",&a,&b); 
        if(a==b){
            printf("%lld\n",a);
        }
        else{
            memset(bin1,0,sizeof(bin1));
            memset(bin2,0,sizeof(bin2));
            while(a!=0){
                int lin=a%2;
                bin1[i++]=lin;
                a/=2;
            }
            while(b!=0){
                int lin=b%2;
                bin2[j++]=lin;
                b/=2;
            }
            for(int k=max(i,j)-1;k>=0;k--){
                if(bin1[k]!=bin2[k]){
                    ans+=(ll)pow(2,k+1)-1;
                    break;
                }
                else{
                    if(bin1[k]==1){
                        ans+=(ll)pow(2,k);
                    }

                }
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_37774171/article/details/81981347