我认为关键是首先了解 K 值的模式及其增长速度。基本上,你有:
K(1) = 0
K(X) = K(bitcount(X))+1 for X > 1
因此找到给定 K 的最小 X 值,我们看到
K(1) = 0
K(2) = 1
K(3) = 2
K(7) = 3
K(127) = 4
K(170141183460469231731687303715884105727) = 5
所以对于像这样的例子48238 10^18 9
答案很简单就是 0。K=0 仅适用于 1,K=1 仅适用于 2 的幂,因此在感兴趣的范围内,我们几乎只会看到 K 值 2、3 或 4,而永远看不到 K >= 5
edit
好的,所以我们正在寻找一种算法来计算 LO..HI 值范围内 K=2,3,4 的值的数量,而无需迭代整个范围。因此,第一步是找到 bitcount(x)==i 范围内的值的数量,其中 i = 1..59(因为我们只关心 10^18 以内的值和 10^18
edit(再次修复为与 C89 兼容并适用于 lo=1/k=0)
这是一个 C 程序,用于执行我之前描述的操作:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int bitcount(long long x) {
int rv = 0;
while(x) { rv++; x &= x-1; }
return rv; }
long long choose(long long m, long long n) {
long long rv = 1;
int i;
for (i = 0; i < n; i++) {
rv *= m-i;
rv /= i+1; }
return rv; }
void bitcounts_p2range(long long *counts, long long base, int l2range) {
int i;
assert((base & ((1LL << l2range) - 1)) == 0);
counts += bitcount(base);
for (i = 0; i <= l2range; i++)
counts[i] += choose(l2range, i); }
void bitcounts_range(long long *counts, long long lo, long long hi) {
int l2range = 0;
while (lo + (1LL << l2range) - 1 <= hi) {
if (lo & (1LL << l2range)) {
bitcounts_p2range(counts, lo, l2range);
lo += 1LL << l2range; }
l2range++; }
while (l2range >= 0) {
if (lo + (1LL << l2range) - 1 <= hi) {
bitcounts_p2range(counts, lo, l2range);
lo += 1LL << l2range; }
l2range--; }
assert(lo == hi+1); }
int K(int x) {
int rv = 0;
while(x > 1) {
x = bitcount(x);
rv++; }
return rv; }
int main() {
long long counts[64];
long long lo, hi, total;
int i, k;
while (scanf("%lld%lld%d", &lo, &hi, &k) == 3) {
if (lo < 1 || lo > hi || k < 0) break;
if (lo == 0 || hi == 0 || k == 0) break;
total = 0;
if (lo == 1) {
lo++;
if (k == 0) total++; }
memset(counts, 0, sizeof(counts));
bitcounts_range(counts, lo, hi);
for (i = 1; i < 64; i++)
if (K(i)+1 == k)
total += counts[i];
printf("%lld\n", total); }
return 0; }
对于 2^63-1 (LONGLONG_MAX) 以内的值,它运行得很好。
为了48238 1000000000000000000 3
它给513162479025364957
,这看起来确实合理
edit
给出输入
48238 1000000000000000000 1
48238 1000000000000000000 2
48238 1000000000000000000 3
48238 1000000000000000000 4
给出输出
44
87878254941659920
513162479025364957
398959266032926842
这些加起来是 999999999999951763,这是正确的。 k=1 的值是正确的(2^16 到 2^59 范围内有 44 个 2 的幂)。因此,虽然我不确定其他 3 个值是否正确,但它们肯定是合理的。