题目链接:HDU - 5969
题意:找出区间[L, R]中的两个数x、y,使x|y(位或)最大。
题解:位或是二进制运算,二进制中只有0和1,要使位或最大,就要使R位或后的1尽可能的多。因为位或的性质,不可能位或后使数的最高位大于R。所以其中一个数必须是R。首先要知道,在剩下的数中能使R增加的1的位数是有限的。那么能增加多少呢?能使L与R出现的L的最高不同位之后的低位全部变成1。
例:R:10100010 能产生最大位或的数:R:10100010 位或结果:10111111
L:10011000 x:10011111
可以将上面R的绿色位全部变成1。
这是因为一个数x从L开始增大到R,x与R出现的x的最高不同位不能超过L与R的L的最高不同位。如样例中x与R最高不同位不能超过红色位。因为能产生最的位或的x必须满足与R的最高不同位之后的位全部是1,如紫色的部分,这样位或后能使R的相同部分全变成1,而如果此时让紫色位1继续增多,那么会使x大于R,不满足条件。
操作:
1.取K = R ^ L;这样能将R与L所有不同的位都标记出来。例中的K = 00111010
2.求出求出K的最高位的位数d(例K的蓝色位),令x = (1 << d) - 1。这样能使最高不同位后的位全部变成1。例中的x = 00011111
3.ans = R | x
#include <bits/stdc++.h>
using namespace std;
//求出最高位
int digit(long long K)
{
int d = 0;
while(K > 0){
K >>= 1;
d++;
}
return d;
}
int main()
{
int T;
long long L, R, ans, K, x, d;
scanf("%d", &T);
while(T--){
scanf("%I64d%I64d", &L, &R);
K = R ^ L;
d = digit(K);
x = (1LL << d) - 1;
printf("%I64d\n", R | x);
}
return 0;
}