题意:
从[A,B]中选若干个数(至少1个),进行位运算or,能得到多少个不同的结果。
题解:
考试时想到的离AC特别近,但是就差了一步…亏亏亏。
如果A=B,答案显然是1.所以考虑A<B。
首先我们可以把两个数最前面相同的部分减掉,可以发现这不影响答案(我差的就是这一步)。然后二者之间就一定会有若干个2的次方。根据找规律可以发现,对每一个i,使第i位必须取1,前面为0,后面任取,所以这个i的答案由
[
a
,
m
i
n
(
b
,
2
∗
i
−
1
)
]
[a,min(b,2*i-1)]
[a,min(b,2∗i−1)]计算得到。
令
x
<
2
i
x<2^i
x<2i,那么
[
x
,
2
i
)
[x,2^i)
[x,2i)之间可以得到
2
i
−
x
2^i-x
2i−x个不同的结果。再令
2
i
≤
x
<
2
i
+
1
2^i\le x\lt 2^i+1
2i≤x<2i+1,可以发现
[
2
i
,
x
]
[2^i,x]
[2i,x]可以得到的结果有1,2,4,4,8,8,8,8,…的规律。因为一个是从前往后,一个从后往前,所以加起来和
2
i
2^i
2i取min就是当前的i的答案,求和即可。
代码:
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
LL Get(LL l,LL r)
{
LL tmp=r-l+1,i;
for(i=1;i<tmp;i*=2ll);
return i;
}
int main()
{
LL a,b,t,ans=0;
scanf("%lld%lld",&a,&b);
if(a==b) { printf("1\n"); return 0; }
for(t=1;t<a;t*=2ll);
while(t>b)
{
t/=2;
if(a&t) a-=t,b-=t;
}
ans+=t-a;
for(;t<=b;t*=2ll) ans+=min(t-a+Get(t,min(2ll*t-1,b)),t);
printf("%lld\n",ans);
}