感谢 Morning_Glory 赞助
异
或
异或
异或
D
e
s
c
r
i
p
t
i
o
n
\mathcal{Description}
Description
给定
L
,
R
L, R
L,R, 求
∑
i
=
L
R
∑
j
=
L
R
i
⊕
j
\sum_{i=L}^R\sum_{j=L}^R\ i⊕j
i=L∑Rj=L∑R i⊕j
L
,
R
<
=
1
0
9
L,R <=10^9
L,R<=109 .
S
o
l
u
t
i
o
n
\mathcal{Solution}
Solution
假设
L
=
1
,
R
=
4
L=1, R=4
L=1,R=4, 则将所有涉及到的数字转换为 二进制 如下
↓
↓
↓,
[
1
∣
0
0
1
2
∣
0
1
0
3
∣
0
1
1
4
∣
1
0
0
]
\ \\ \begin{bmatrix} 1\ |\ 0\ 0\ 1 \\ 2\ |\ 0\ 1\ 0 \\ 3\ |\ 0\ 1\ 1 \\ 4\ |\ 1\ 0\ 0 \\ \end{bmatrix}
⎣⎢⎢⎡1 ∣ 0 0 12 ∣ 0 1 03 ∣ 0 1 14 ∣ 1 0 0⎦⎥⎥⎤
按
位
处
理
:
按位处理 :
按位处理:
以 2 0 2^0 20位 为例,
[
1
0
1
0
]
\ \\ \begin{bmatrix} 1 \\ 0 \\ 1 \\ 0 \\ \end{bmatrix}
⎣⎢⎢⎡1010⎦⎥⎥⎤
每个数字都要与每个数字 异或 并且对答案造成贡献,
设
0
的
数
量
为
n
u
m
0
,
1
的
数
量
的
为
n
u
m
1
设\ 0\ 的数量为\ num_0, 1\ 的数量的为\ num_1
设 0 的数量为 num0,1 的数量的为 num1
- 当前位置为 1 1 1, 对答案贡献为 n u m 0 num_0 num0 .
- 当前位置为 0 0 0, 对答案贡献为 n u m 1 num_1 num1 .
综上该位答案为 2 ∗ n u m 1 ∗ n u m 0 ∗ 2 0 2*num_1*num_0*2^0 2∗num1∗num0∗20 .
求
n
u
m
1
,
n
u
m
0
:
求num_1, num_0:
求num1,num0:
[
0
0
0
0
0
1
0
1
0
0
1
1
1
0
0
1
0
1
1
1
0
1
1
1
]
\begin{bmatrix} 0\ 0\ 0 \\ 0\ 0\ 1 \\ 0\ 1\ 0 \\ 0\ 1\ 1 \\ 1\ 0\ 0 \\ 1\ 0\ 1 \\ 1\ 1\ 0 \\ 1\ 1\ 1 \\ \end{bmatrix}
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡0 0 00 0 10 1 00 1 11 0 01 0 11 1 01 1 1⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
观察以上序列, 发现若当前位置为
2
i
2^i
2i位, 则
000..111...
000..111...
000..111...循环节长度为
2
i
+
1
2^{i+1}
2i+1.
先来求
[
0
,
N
]
[0, N]
[0,N] 中
2
i
2^i
2i 位置的答案,
则
n
u
m
0
=
⌊
N
+
1
2
i
+
1
⌋
∗
2
i
+
m
i
n
{
(
N
+
1
)
%
2
i
+
1
,
2
i
}
n
u
m
1
=
N
−
n
u
m
0
+
1
num_0 = \lfloor \frac{N+1}{2^{i+1}} \rfloor* 2^i + min\{(N+1)\%2^{i+1}, 2^i\}\\ \ \\ num_1 = N-num_0+1
num0=⌊2i+1N+1⌋∗2i+min{(N+1)%2i+1,2i} num1=N−num0+1
然后 容斥 即可求出 [ L , R ] [L, R] [L,R] 的 n u m 0 , n u m 1 num_0, num_1 num0,num1 .
复
杂
度
O
(
l
o
g
N
)
复杂度 O(logN)
复杂度O(logN).
C
o
d
e
\mathcal{Code}
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;
}