这几天做fwj大佬在Vj上放出来的训练题,遇见很多思维题。比如下边这道题。
B君和G君聊天的时候想到了如下的问题。
给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大。
其中|表示按位或,即C、 C++、 Java中的|运算。
Input包含至多10001组测试数据。
第一行有一个正整数,表示数据的组数。
接下来每一行表示一组数据,包含两个整数l,r。
保证 0 <= l <= r <= 10181018。Output对于每组数据输出一行,表示最大的位或。Sample Input
5
1 10
0 1
1023 1024
233 322
1000000000000000000 1000000000000000000
Sample Output
15
1
2047
511
1000000000000000000
题意:给你两个数l r让你输出l--r之间最大的按位或的结果(2个整数)
在刚开始做这道题的时候,想到过肯定是是把最大的保存下来。然后在从下边的找一个出来。但是一直想不到怎么去找那个剩余的值。在fwj大佬在讲解题目之后。恍然大悟(顿时豁然开朗啊)。
接下来举个例子
5 101
6 110
7 111
8 1000
9 1001
10 1010
11 1011
12 1100
13 1101
14 1110
15 1111
1、我们先看5->10 在这个区间中。我们可以看到5的二进制位数和10的二进制位数是不相等的。那么我们就可在这两个数之间找到1个7(2进制为111)那么此时10|7为最大15;
2、当位数相同的情况下,比如8->10那么我们在去掉8和10(从二进制开始到找到不同)相同的位数;
我们可以看到此时 8 剩下----- 00
10 剩下------10
那么我们可以看到在00---->10之间我们可以找到一个01使得我们的按位或是最大的。
那么,根据这个想法。我们就可以很快的写出我们的代码了;
代码:
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<math.h>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define pi acos(-1)
#define close ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N=1000000+50;
const int INF=0x3f3f3f3f;
const double EPS = 1e-10;
ll mod = 1e9+7;
ll Get_Sum(ll l,ll r){
ll numl[10000];
ll numr[10000];
memset(numl,-1,sizeof(numl));
memset(numr,-1,sizeof(numr));
int cntl = 0, cntr = 0;
while(l){
numl[cntl++] = l % 2;
l /= 2;
}
while(r){
numr[cntr++] = r % 2;
r /= 2;
}
if(cntr > cntl) cout<<((ll)pow(2,cntr)-1)<<endl;
else{
int flag = 0;
for(int i = cntr - 1; i >= 0; i--){
if(numl[i] != numr[i]){
flag = i;
break;
}
}
ll ans = 0;
for(int i = cntr - 1; i >= 0; i--){
if(i < flag){
ans += (ll)pow(2,i);
}
else if(numr[i] == 1){
ans += (ll)pow(2,i);
}
}
cout<<ans<<endl;
}
}
int main(){
close;
int t;
cin>>t;
while(t--){
ll l, r;
cin>>l>>r;
if(l == r) cout<<r<<endl;
else Get_Sum(l,r);
}
return 0;
}
/*
********
************
####....#.
#..###.....##....
###.......###### ### ###
........... #...# #...#
##*####### #.#.# #.#.#
####*******###### #.#.# #.#.#
...#***.****.*###.... #...# #...#
....**********##..... ### ###
....**** *****....
#### ####
###### ######
##############################################################
#...#......#.##...#......#.##...#......#.##------------------#
###########################################------------------#
#..#....#....##..#....#....##..#....#....#####################
########################################## #----------#
#.....#......##.....#......##.....#......# #----------#
########################################## #----------#
#.#..#....#..##.#..#....#..##.#..#....#..# #----------#
########################################## ############
*/
大佬cqw的另一种思想(厉害!厉害!)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//求最大位数
int Max_Pow(ll x){
int d = 0;
while(x > 0){
x >>= 1;
d++;
}
return d;
}
int main(){
int t;
ll l, r, x, d, ans;
scanf("%d",&t);
while(t--){
scanf("%I64dd%I64d",&l, &r);
x = r ^ l;
d = Max_Pow(x);
ans = (1LL << d) - 1;
printf("%I64d\n",R | x);
}
}