数位运算
把n拆成二进制 (1xxxxxxx) 形式,对于任意 i 拆成相同位数的二进制,如果最高位是0,那么一定是可以完全流完,因为 i xor n > i (i xor n 最高位一定是1),所以可以用求和公式来求。对于最高位是1,那么后面的位数就是相当于数位的运算,计算每一位的贡献。如果当前位为1,当且 i 的对应位为0时有贡献,维护一下很容易求出有多少个合法的解;同理当前位为0。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const ll mo = 1000000007;
ll n, t, ans, a[100], g[100], l, r;
void init() {
ans = 0;
memset(a, 0, sizeof(a));
}
ll mul(ll x, ll y) {
ll t = 0;
while (y) {
if (y%2) t = (t+x)%mo;
y /= 2;
x *= 2;
}
return t;
}
int main() {
freopen("input.txt","r",stdin); freopen("e.out","w",stdout);
while (scanf("%lld", &n) != EOF) {
init();
n--;
t = 1;
while (t*2 <= n) t *= 2;
l = t%mo; r = (t-1)%mo;
if (l%2 == 0) l /= 2;
else r /= 2;
ans = (l*r%mo+n%mo)%mo;
n = n-t;
while (n) {
a[++a[0]] = n%2;
n /= 2;
}
r = 1;
for (int i = 1; i < a[0]; i++) r *= 2;
l = 0;
g[1] = 1;
for (int i = 2; i <= a[0]; i++) g[i] = (g[i-1]*2)%mo;
for (int i = a[0]; i >= 1; i--) {
if (a[i]) {
ans = (ans+(( ((l+1)%mo) * (r%mo) %mo )* (g[i]%mo) )%mo)%mo;/*2^(i-1)*/
} else {
ans = (ans+((l%mo) * (r%mo) %mo )*(g[i]%mo) %mo)%mo;
}
l = l*2+a[i];
r = r/2;
}
printf("%lld\n", ans);
}
}