题目链接:点我
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;
}