Codefroces 485C Bits【贪心+思维】好题

C. Bits
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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.

Input

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).

Output

For each query print the answer in a separate line.

Examples
Input
3
1 2
2 4
1 10
Output
1
3
7
Note

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);
        }
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值