求区间[l,r]中的数任意互相异或之后有多少种可能的结果
l<=r<=1e18,数据组数<=100
这种题一眼线性基啦~
虽然我并不太熟练,还自己推了一遍插入
这样直接暴力做有50分
然后打了个表发现了一个规律:
首先l一定会在线性基中,
然后我们知道了线性基中的最后一个数,想要快速找出线性基中的下一个数
假设当前的数的二进制表示是 10100,那么接下来的会是
10100
10101
10110
11000
11100
也就是每次找当前最后一个数中,从最低位起第一个当前位为0且线性基为空的位置
然后这一位是1,后面就都是0,并插入到这一位的线性基中
感性理解一下好像没什么毛病
那就直接模拟这个过程就好了,复杂度O(T log^2 L)
#include
#include
#include
#define fo(i,a,b) for(ll i=a;i<=b;i++)
#define fd(i,a,b) for(ll i=a;i>=b;i--)
using namespace std;
typedef long long ll;
ll l,r,ans,a[61],mi[61];
int main() {
freopen("A.in","r",stdin);
freopen("A.out","w",stdout);
int ty;
mi[0]=1;fo(i,1,60) mi[i]=mi[i-1]*2;
for(scanf("%d",&ty);ty;ty--) {
scanf("%lld%lld",&l,&r);
if (!l&&!r) {
printf("1\n");
continue;
}
fo(i,0,60) a[i]=0;
ll x=l;ans=2;if (!x) x=1;
fd(i,60,0) if (x&mi[i]) {a[i]=x;break;}
while (xint now=61;
fo(i,0,60)
if (!a[i]&&!(x&mi[i])) {
now=i;
break;
}
if (now>60) break;
fo(i,0,now-1) if (x&mi[i]) x-=mi[i];
x+=mi[now];a[now]=x;
if (x<=r) ans=ans*2;
}
printf("%lld\n",ans);
}
}