计算a^b==a+b在(l,r)的对数Codeforces Round #597 (Div. 2)
题:https://codeforces.com/contest/1245/problem/F
分析:转化为:求区间内满足a&b==0的对数(解释见代码)
///求满足a&b==0在区间【l,r】的对数 ///推导:区间[2l,2r]可由[l,r]乘3倍得来 ///原因:*2我们可以看成事左移1位,那么这个位置上,对于俩个数来说 /////////可以取0,1 或1,0或0,0才依然满足 a&b==0这个题目条件 /////////这个公式可以用递归推导回溯计算, /////////当我们回递归到区间为奇数的情况的时候,我们想办法让它变成偶数 /////////假设[a,b]中a是奇数,那么我们就把它弄成a+1,然后加上漏算的部分即可 /////////g(x,y)表示在区间[0,b]中和x满足题目条件的个数 /////////然后漏算的部分就是 (g(a,b)-g(a,a))*2 /////////b为奇数的情况也照样这样分析 /////////完 #include<bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back ll g(int a,int b){ ll ans=0; ll num=0; for(int i=1;i<=b;i<<=1){ if(i&b){ b^=i; if(!(a&b)) ans+=1ll<<num; } if(!(i&a)){///a在二进制下i位置为0的情况下,num就是计数这种情况的 num++; } } return ans; } ll cal(int a,int b){ if(a==0) return 2*b-1+cal(1,b); if(a==b) return 0; ll ans=0; if(a&1){///若左区间的值为奇数 ans+=(g(a,b)-g(a,a))*2;///乘2是对数可以互换,然后这个就是剪掉区间缩成偶数时加上漏加的部分,类似于用前缀和算区间和 a++; } if(b&1){///若右区间的值为偶数 ans+=(g(b-1,b)-g(b-1,a))*2; b--; } return ans+3*cal(a/2,b/2); } int main(){ int t; scanf("%d",&t); while(t--){ int a,b; scanf("%d%d",&a,&b); printf("%I64d\n",cal(a,b+1)); } return 0; }