题意
给出b,a,问用区间[b,a]中的数可以通过or运算得到多少个不同的数。
a,b<=2^60
分析
设a和b的最高不同位为d,a从d开始的第二个非零位为k。我们把所有数分成两部分,第一部分是d位上是1。
显然不管选哪几个数进行or运算,d之前的位置都是相同的,所以不妨把d之前的位去掉。
先对每个部分单独考虑。
对于第二部分
[b,2d−1]
[
b
,
2
d
−
1
]
,显然两个数or起来的结果不会小于两个数中较大的那个,所以只用第二部分的数可以得到
[b,2d−1]
[
b
,
2
d
−
1
]
中的数。
对于第一部分
[2d,a]
[
2
d
,
a
]
,不难发现不管怎么选数,k之前的位置都是一样的。考虑从k位开始的位置,我们既可以选10…0也可以选00…0,然后k后面的位置就可以任意取了。所以可以得到
[2d,2d+2k+1−1]
[
2
d
,
2
d
+
2
k
+
1
−
1
]
中的数。
如果两部分都要用的话,d位上一定是1,且d位后的最小是b,最大是
2d−1
2
d
−
1
,所以能得到
[2d+b,2d+1−1]
[
2
d
+
b
,
2
d
+
1
−
1
]
中的数。
三个区间取并集就好了。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL a,b,bin[65];
int main()
{
scanf("%lld%lld",&b,&a);
if (a==b) {puts("1");return 0;}
bin[0]=1;
for (int i=1;i<=60;i++) bin[i]=bin[i-1]*2;
int d=60;
while ((a&bin[d])==(b&bin[d])) d--;
a&=bin[d+1]-1;b&=bin[d+1]-1;
int k=d-1;
while (k>=0&&!(a&bin[k])) k--;
LL l1=b,r1=bin[d]+bin[k+1]-1,l2=bin[d]+b,r2=bin[d+1]-1;
l2=max(l2,r1+1);
printf("%lld",r1-l1+1+max((LL)0,r2-l2+1));
return 0;
}