题目分析:
首先明确一点,0<=l<=r<=1e9 l*r不会爆long long
所以尽管开long long就ok
由 a+b=a^b 异或是不进位的加法
如果要满足这样的性质,那么得确定一点,只要不两个位置同时为1就ok
对于这种数位统计类的问题我们一般用数位dp来做
即保存好状态,分别确定从[1,r]和[1,l-1]中满足情况的数,然后利用容斥原理来减去,
这样就可知道[l,r]区间内满足情况的的数的个数
为什么要这样搞呢???????
因为这个东西的本质是暴力穷举,即从数位高的向数位低的搜索,这样其实等效与一次暴力
枚举??????
只是我们可以设置状态,在pos以前满足一些条件的话??????
我们就可以把接下来的存下来了,就直接输出就可
这样可以看作是一次动态规划的过程???
其实本质是记忆化搜素
但是我们发现一个点,这个有两个操作数,那么就变成二维的一个操作了??????
我们可以继续用容斥的思想来搞
那么[l,r]区间满足条件的画就有 f(r,r)-2*f(l-1,r)+f(l-1,l-1)
dp的过程这个是100组,而且每次都会换不同的[l,r],建议采用把限制条件也加入的做法
这样可以快点,不会超时
如果这个i的当前为1 且j的当前为1 那么就不往下操作就可。
最后穿完所有的数还合法的方案就+1
记录一下方案数即可
/*
题目分析:
首先明确一点,0<=l<=r<=1e9 l*r不会爆long long
所以尽管开long long就ok
由 a+b=a^b 异或是不进位的加法
如果要满足这样的性质,那么得确定一点,只要不两个位置同时为1就ok
对于这种数位统计类的问题我们一般用数位dp来做
即保存好状态,分别确定从[1,r]和[1,l-1]中满足情况的数,然后利用容斥原理来减去,
这样就可知道[l,r]区间内满足情况的的数的个数
为什么要这样搞呢???????
因为这个东西的本质是暴力穷举,即从数位高的向数位低的搜索,这样其实等效与一次暴力
枚举??????
只是我们可以设置状态,在pos以前满足一些条件的话??????
我们就可以把接下来的存下来了,就直接输出就可
这样可以看作是一次动态规划的过程???
其实本质是记忆化搜素
但是我们发现一个点,这个有两个操作数,那么就变成二维的一个操作了??????
我们可以继续用容斥的思想来搞
那么[l,r]区间满足条件的画就有 f(r,r)-2*f(l-1,r)+f(l-1,l-1)
dp的过程这个是100组,而且每次都会换不同的[l,r],建议采用把限制条件也加入的做法
这样可以快点,不会超时
如果这个i的当前为1 且j的当前为1 那么就不往下操作就可。
最后穿完所有的数还合法的方案就+1
记录一下方案数即可
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <bitset>
typedef long long ll;
using namespace std;
ll dp[37][2][2];
int t;
ll l,r,L,R;
ll dfs(int pos,int lim_x,int lim_y){
if(pos==-1) return 1;
if(dp[pos][lim_x][lim_y]!=-1) return dp[pos][lim_x][lim_y];
int up_x=lim_x?((int)L>>pos)&1:1;
int up_y=lim_y?((int)R>>pos)&1:1;
ll ans=0;
for(int i=0;i<=up_x;i++){
for(int j=0;j<=up_y;j++){
if(!(i&j)){
ans+=dfs(pos-1,lim_x&(i==up_x),lim_y&(j==up_y));
}
}
}
dp[pos][lim_x][lim_y]=ans;
return ans;
}
ll solve(ll st,ll ed){
if(st<0) return 0;
L=st;R=ed;
memset(dp,-1,sizeof(dp));
int cnt=0;
while(ed){ed/=2;cnt++;}
return dfs(cnt-1,1,1);
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&l,&r);
printf("%lld\n",solve(r,r)-2*solve(l-1,r)+solve(l-1,l-1));
}
return 0;
}