Description
给定一个区间[A,B],问从区间内任意取出一些数字,它们或出的不同结果有多少种
A
,
B
≤
2
60
A,B\le2^{60}
A,B≤260
Solution
考虑转成二进制来做。A和B相同的最高几位都是没用的,扔掉
记F是A和B从高到低第一位不同的二进制位,S是B从高到低第二位为1的二进制位
我们可以把区间分成两份,也就是
[
A
,
2
F
−
1
]
[A,2^F-1]
[A,2F−1]和
[
2
F
,
B
]
[2^F,B]
[2F,B]
只用左边可以做出
[
A
,
2
F
−
1
]
[A,2^F-1]
[A,2F−1]的数①
只用右边可以做出
[
2
F
,
2
F
+
2
S
+
1
−
1
]
[2^F,2^F+2^{S+1}-1]
[2F,2F+2S+1−1]②
既用左边又用右边可以做出
[
2
F
+
A
,
2
F
+
1
−
1
]
[2^F+A,2^{F+1}-1]
[2F+A,2F+1−1]③
要推这个的话只需要记住这是连续的区间就可以了。。
我们发现①和②是连续的,那么考虑三个区间的并集就很方便了
需要注意A=B的情况和B除了F外没有1的位的情况,当然如果写得好当我没说。。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (LL i=st;i<=ed;++i)
#define drp(i,st,ed) for (LL i=st;i>=ed;--i)
typedef long long LL;
int main(void) {
LL a,b; scanf("%lld%lld",&a,&b);
if (a==b) return 0&puts("1");
drp(i,60,0) if (((a>>i)&1)!=((b>>i)&1)) {
LL r=1LL<<i,k=0;
a&=(r*2LL-1); b&=(r*2LL-1);
drp(j,i-1,0) if ((b>>j)&1) {
k=1LL<<j;
break;
}
if (!k) k=1;
else k=k*2LL;
LL ans;
if (r+a<=r+k) ans=r*2LL-a;
else ans=r+k-a+r*2LL-r-a;
printf("%lld\n", ans);
break;
}
return 0;
}