区间或和-(位运算)

链接:https://ac.nowcoder.com/acm/contest/332/G
来源:牛客网

题目描述

求a|(a+1)|(a+2)|...|(b-1)|b。

其中|表示[按位或](https://baike.baidu.com/item/%E6%8C%89%E4%BD%8D%E6%88%96)。

输入描述:

多组输入,每行两个数表示a和b

输出描述:

对于每组输入,输出一个数a|(a+1)|(a+2)|...|(b-1)|b。
示例1

输入

99 109
68 77
55 66
34 43
1111234 1114321

输出

111
79
127
47
1179647

备注:

输入不超过10000行,0a,b10180≤a,b≤1018,ab

思路分析:
1.位运算,肯定是用二进制做题啦
2.a<=b,二进制从左往右数,肯定有某个位,有b为1,a为0,连续或运算,会把后面的位都用1填满就是结果了
比如
a=1100001110
b=1101010110
c=1101111111
从左往右数第四位开始用1补满

#include<stdio.h>
#include<math.h>
#include<string.h>
#include<algorithm>
#include<string>
#include<vector>
#include<iostream>
#include<cstring>
#define inf 0x3f3f3f3f
using namespace std;
#define ll long long
ll two[65];
string s1,s2;
void init()//打印2的次方表
{
    two[0]=1;
    for(int i=1;i<=62;i++)
        two[i]=two[i-1]*2;
}
string trans(ll x)//把数字转化为二进制的字符串
{
    string res="";
    ll r;
    while(x)
    {
        r=x%2;
        res=char(r+'0') + res;
        x=x/2;
    }
    return res;
}

void addzero()//字符串长度不同则前面补0
{
    int len1=s1.size();
    int len2=s2.size();
    for(int i=1;i<=len2-len1;i++)
        s1='0'+s1;
}

int num()//出现第一个不同的数位从右往左第几位
{
    int len=s1.size();
    for(int i=0;i<len;i++)
    {
        if(s1[i]!=s2[i])
            return (len-i);
    }
    return 0;
}

ll add(int x)//累计多出的那一段
{
    ll res=0;
    for(int i=0;i<x;i++)
        res+=two[i];
    return res;
}

int main()
{
    ll a,b;
    init();
    while(scanf("%lld%lld",&a,&b)!=EOF)
    {
        s1=trans(a);
        s2=trans(b);
        addzero();
        ll more = add( num() );
        ll ans = b|more;
        printf("%lld\n",ans);
    }
    return 0;
}

 



posted @ 2019-02-07 16:24  守林鸟  阅读(1110)  评论(0编辑  收藏  举报