最大的位或
问题:给定自然数l和r ,选取2个整数x,y满足l <= x <= y <= r ,使得x|y最大,其中|是或运算。
包含至多10001组测试数据。第一行有一个正整数,表示数据的组数。 接下来每一行表示一组数据,包含两个整数l,r。
(保证 0 <= l <= r <= 10^18。)
- 做题前思路很重要!
- 思路:
- 1、先将较大的数转化为二进制.
while (m)//转化二进制
{
bin[p++]=m%2;
m/=2;
}
- 2、最重要的代码
for(i=0;i<p;i++)
{
if(bin[i]==0)
{
if((max-sum-1)>=n)
bin[i]=1;
}
else
sum+=chan_pow(i);
}
标注:此时的sum作为进制,以l=2,r=10为例子。
- 10二进制为‘1010’,第0位为‘0’,(max-sum-1)=9,9的第0位为1,或运算将其转为1.
- 同理,10的第二位为1,此时sum=2**1.
- 10的第三位为‘0’,(max-sum-1)作用是帮助找到对应位最近的1.
- 若对应位最近的的数大于最小数l(或者本题设置的n),则 若对应位最近的的数大于等于最小数l(或者本题设置的n),则或运算变为‘1’即可。
| 3 | 2 | 1 | 0 |
| 0 | 0 | 0 | 1 |----------- 1
| 0 | 0 | 1 | 0 |------------2
| 0 | 0 | 1 | 1 |-------------3
| 0 | 1 | 0 | 0 |-------------4
| 0 | 1 | 0 | 1 |------------- 5
| 0 | 1 | 1 | 0 |--------------6
| 0 | 1 | 1 | 1 |---------------7
| 1 | 0 | 0 | 0 |--------------8
| 1 | 0 | 0 | 1 |---------------9
| 1 | 0 | 1 | 0 |--------------10
- 3、最后将其输出即可。
for(i=0;i<p;i++)
{
if(bin[i]==1)
sum+=chan_pow(i);
}
思路会了,上代码!
#include <stdio.h>
long long int chan_pow(int a)//二进制转化成十进制的函数
{
long long int t=1;
int i;
for(i=0;i<a;i++)
{
t=t*2;
}
return t;
}
int main(int argc, char *argv[]) {
int N,i;
int bin[10000];
long long int m,n;
scanf("%d",&N);
while (N--)
{
scanf("%lld %lld",&n,&m);
long long int max=m;
long long int sum=0;
int p=0;//二进制的位数
while (m)//转化二进制
{
bin[p++]=m%2;
m/=2;
}
for(i=0;i<p;i++)
{
if(bin[i]==0)
{
if((max-sum-1)>=n)
bin[i]=1;
}
else
sum+=chan_pow(i);
}
sum=0;
for(i=0;i<p;i++)
{
if(bin[i]==1)
sum+=chan_pow(i);
}
printf("%lld\n",sum);
}
}
思考:也可以将最小数转化为二进制进行计算,此时改为(min+sum+1)进行计算即可。