Let's denote as the number of bits set ('1' bits) in the binary representation of the non-negative integer x.
You are given multiple queries consisting of pairs of integers l and r. For each query, find the x, such that l ≤ x ≤ r, and is maximum possible. If there are multiple such numbers find the smallest of them.
The first line contains integer n — the number of queries (1 ≤ n ≤ 10000).
Each of the following n lines contain two integers li, ri — the arguments for the corresponding query (0 ≤ li ≤ ri ≤ 1018).
For each query print the answer in a separate line.
3 1 2 2 4 1 10
1 3 7
The binary representations of numbers from 1 to 10 are listed below:
110 = 12
210 = 102
310 = 112
410 = 1002
510 = 1012
610 = 1102
710 = 1112
810 = 10002
910 = 10012
1010 = 10102
题目大意;
有n个询问,每次询问输入两个数l,r,让你找一个数在【l,r】区间内,使其二进制数中1的个数最多。如果个数相同情况下,输出小的数。比如5和3:101 011,1的个数相同,但是优先输出3.
思路:
1、因为我们要找的解是区间【l,r】内二进制数中1的个数最多的那个数,所以我们贪心的点一定是在1的个数上边。
2、假设数字l的二进制数表达式中,如果有0的存在,那么我们肯定优先将这些0补成1。比如:
8的二进制数为:1000,我们肯定不是优先在当前数上添加位数而是先补上对应位置的0.而且因为填上越靠近末尾的0.花费越少,所以我们从末尾开始补0,如果当这个0补上1,而且补上的数还小于等于r,那么我们这个1就是可以补上的,然后继续判断下一位(对应补最末尾的数需要1,接下来需要2,接下来需要4...............)。
3、那么如果我们按照上述过程补0之后,再考虑增加二进制数长度的问题。而且在增加长度的同时,一定是要添加1的,而不是添加0.因为添加0毫无意义。
假如有这样一个数:
5的二进制数位:101,此时r=30,那么我们首先按照第一步将l的二进制数中的0补成1:
5------------->7 二进制数:111.此时我们再考虑增加其长度:
7------------>15 二进制数:1111,此时我们再考虑增加一个长度:
7------------->31 二进制数:11111,但是此时31 > 30,当前数不在【l,r】区间内,那么其解就是:15(1111);
Ac代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
using namespace std;
#define ll __int64
int num[25];
int getnum(ll x)
{
int cont=0;
while(x)
{
num[cont++]=x%2;
x/=2;
}
return cont;
for(int i=0;i<cont;i++)
{
printf("%d",num[i]);
}
printf("\n");
}
int main()
{
int n;
while(~scanf("%d",&n))
{
while(n--)
{
ll l,r;
scanf("%I64d%I64d",&l,&r);
int len=getnum(l);
ll ans=l;
for(int i=0;i<len;i++)
{
if(num[i]==0)
{
ll tmp=(ll)(pow(2,i));
if(ans+tmp<=r)
ans+=tmp;
}
}
for(int i=len;;i++)
{
ll tmp=(ll)(pow(2,i));
if(ans+tmp<=r)
ans+=tmp;
else break;
}
printf("%I64d\n",ans);
}
}
}