题目大意 :
解题思路:
这里有个很核心的地方就是 log2(i+j) \text{log2(i+j)} log2(i+j)本质上就是看看 i+j \text{i+j} i+j的二进制高位在哪里?
那么上面的式子本质上就可以化简成所以 i & j = = 0 i\&j==0 i&j==0的情况下那些 i + j i+j i+j二进制高位之和
但是这么求比较麻烦:我们可以转化一下:
就是去枚举高位看看在二进制高位固定死的情况下有多少对
i
&
j
=
=
0
i\&j==0
i&j==0假设是
x
h
x_h
xh个,那么答案就是:
∑
h
=
0
32
x
h
∗
(
h
+
1
)
\sum_{h=0}^{32}x_h*(h+1)
∑h=032xh∗(h+1)
h
:
是
最
高
位
h:是最高位
h:是最高位
那么这样我们就可以直接数位dp
就是对 i , j i,j i,j分别在 X , Y X,Y X,Y限制下面的数位 d p dp dp
那么就是常规的数位dp上面套两个限制而已
int dfs(int len, int lm1, int lm2, int ff) { // 两个限制就是两个lim
if (len == -1) {
return 1;
}
if (~f[len][lm1][lm2][ff]) return f[len][lm1][lm2][ff];//ff=1说明这是最高位
int up1 = lm1 ? x >> len & 1 : 1;
int up2 = lm2 ? y >> len & 1 : 1; // 对x,y进行限制
int res = 0;
for (int i = 0; i <= up1; i++) { // 两重循环进行限制
for (int j = 0; j <= up2; j++) {
if ((i & j)) continue;
if (ff) {//如果是最高位
if (i | j) {//保证最高位为1.
res = (res + dfs(len - 1, lm1 && i == up1, lm2 && j == up2, 0)) % P;
}
} else {
res = (res + dfs(len - 1, lm1 && i == up1, lm2 && j == up2, 0)) % P;
}
}
}
f[len][lm1][lm2][ff] = res;
return res;
}
AC code
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5, P = 1e9 + 7;
int x, y, ans, f[35][2][2][2];
int dfs(int len, int lm1, int lm2, int ff) {
if (len == -1) {
return 1;
}
if (~f[len][lm1][lm2][ff]) return f[len][lm1][lm2][ff];//ff=1说明这是最高位
int up1 = lm1 ? x >> len & 1 : 1;
int up2 = lm2 ? y >> len & 1 : 1;
int res = 0;
for (int i = 0; i <= up1; i++) {
for (int j = 0; j <= up2; j++) {
if ((i & j)) continue;
if (ff) {//如果是最高:
if (i | j) {//保证最高位为1.
res = (res + dfs(len - 1, lm1 && i == up1, lm2 && j == up2, 0)) % P;
}
} else {
res = (res + dfs(len - 1, lm1 && i == up1, lm2 && j == up2, 0)) % P;
}
}
}
f[len][lm1][lm2][ff] = res;
return res;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %d", &x, &y);
int nx = x, n = 0, ny = y, m = 0;
while (nx) ++n, nx >>= 1;
while (ny) ++m, ny >>= 1;
ans = 0;
memset(f, -1, sizeof f);
/*
x = 0 0 0 0 0 0
y = 0 0 0 0 0 0 0 0 0
*/
for (int i = max(n, m); i >= 0; i--) {
//枚举二进制位的长度。
ans = (ans + 1LL * dfs(i, i >= n - 1 , i >= m - 1, 1) * (i + 1) % P) % P;
}
printf("%d\n", ans);
}
return 0;
}