感谢 Morning_Glory 赞助
异或
Description
给定 L,R, 求
i=L∑Rj=L∑R i⊕j
L,R<=109 .
Solution
假设 L=1,R=4, 则将所有涉及到的数字转换为 二进制 如下 ↓,
⎣⎢⎢⎡1 ∣ 0 0 12 ∣ 0 1 03 ∣ 0 1 14 ∣ 1 0 0⎦⎥⎥⎤
按位处理:
以 20位 为例,
⎣⎢⎢⎡1010⎦⎥⎥⎤
每个数字都要与每个数字 异或 并且对答案造成贡献,
设 0 的数量为 num0,1 的数量的为 num1
- 当前位置为 1, 对答案贡献为 num0 .
- 当前位置为 0, 对答案贡献为 num1 .
综上该位答案为 2∗num1∗num0∗20 .
求num1,num0:
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡0 0 00 0 10 1 00 1 11 0 01 0 11 1 01 1 1⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
观察以上序列, 发现若当前位置为 2i位, 则 000..111...循环节长度为 2i+1.
先来求 [0,N] 中 2i 位置的答案,
则
num0=⌊2i+1N+1⌋∗2i+min{(N+1)%2i+1,2i} num1=N−num0+1
然后 容斥 即可求出 [L,R] 的 num0,num1 .
复杂度O(logN).
Code
#include<bits/stdc++.h>
#define reg register
int read(){
char c;
int s = 0, flag = 1;
while((c=getchar()) && !isdigit(c))
if(c == '-'){ c = getchar(), flag = -1; break ; }
while(isdigit(c)) s = s*10 + c-'0', c = getchar();
return s * flag;
}
const int mod = 1e9 + 7;
int L;
int R;
int Ans;
int pw[50];
int Calc(int x, int b){
return ((x+1)/pw[b+1]) * pw[b] + std::min((x+1)%pw[b+1], pw[b]);
}
void Work(){
L = read(), R = read();
Ans = 0;
for(reg int b = 0; pw[b] <= R; b ++){
int num_0 = Calc(R, b) - Calc(L-1, b), num_1 = R-L+1 - num_0;
int pluss = (2ll*num_0*num_1 % mod) * pw[b] % mod;
Ans = (1ll*pluss + Ans) % mod;
}
printf("%d\n", Ans);
}
int main(){
pw[0] = 1;
for(reg int i = 1; pw[i] <= mod; i ++) pw[i] = pw[i-1] << 1;
int T = read();
while(T --) Work();
return 0;
}