简单的说一下思路
首先对于右边界r,为了计算 0 到 r(闭区间)内有多少个数的二进制包含奇数个1,我们对右边界的二进制格式进行处理。
比如这里我们有一个数的二进制格式为 (一共64位,考虑到题目给定 r 的最大值是
),我们从高位往低位遍历,每当我们碰到了一个1,比如上面这个数最左边第一个1,我们需要考虑的是从
到
之间一共有多少个数的二进制包含奇数个1,问题变成这样就很简单了。一共有5位需要考虑,想让这5位里包含奇数个1,总共有
种01序列,也就是
种。接下来我们碰到第二个1,需要考虑的范围是
到
,想让最后3位包含偶数个1(因为前面已经有了奇数个1),一共有
种01序列,也是
。这样做下去我们就能考虑到从
到
之间的所有情况。
只要能算出来 0 到 r 里有多少个数的二进制包含奇数个1。我们用同样的办法算出 0 到 l-1 里有多少个数,就能很容易的得出从 l 到 r 里有多少个我们需要的数了。
代码如下
#include <bits/stdc++.h>
#include <bitset>
using namespace std;
long long cntt(long long d){
bitset<64> x(d);
long long ans = 0;
int cnt = 0;
for(int i = 63; i > 0; --i){
if(x[i] == 1){
cnt++;
ans += pow(2, i-1);
}
}
// 对最低位需要做一些特殊处理
if(cnt%2 == 1)
++ans;
if(x[0] == 1){
cnt++;
if(cnt%2 == 1)
++ans;
}
return ans;
}
int main(){
int T;
cin >> T;
vector<long long> ans;
for(int k = 0; k < T; ++k){
long long l, r;
cin >> l >> r;
ans.push_back(cntt(r)-cntt(l-1));
}
for(int i = 0; i < ans.size(); i++)
cout << ans[i] << endl;
return 0;
}
京公网安备 11010502036488号