Estou interessado em encontrar uma fórmula simples para determinar a enésima vez que uma determinada contagem de bits ocorre na sequência de números naturais. Especificamente, qual é a relação entre K
e N
na tabela abaixo. Então, por exemplo, qual é o N
de K=123456789123456789123456789
, posso dizer que M
é 50
, mas qual é o N
?
length = 5
for K in range(2**length):
bits = bin(K)[2:].zfill(length)
M = K.bit_count() # numbers of "1"s in the binary sequence
N = sum(1 for i in range(K) if M==i.bit_count())
print(f'{K: <2}',bits,M,N)
'''
K bits M N
0 00000 0 0
1 00001 1 0
2 00010 1 1
3 00011 2 0
4 00100 1 2
5 00101 2 1
6 00110 2 2
7 00111 3 0
8 01000 1 3
9 01001 2 3
10 01010 2 4
11 01011 3 1
12 01100 2 5
13 01101 3 2
14 01110 3 3
15 01111 4 0
16 10000 1 4
17 10001 2 6
18 10010 2 7
19 10011 3 4
20 10100 2 8
21 10101 3 5
22 10110 3 6
23 10111 4 1
24 11000 2 9
25 11001 3 7
26 11010 3 8
27 11011 4 2
28 11100 3 9
29 11101 4 3
30 11110 4 4
31 11111 5 0
...
'''
Então, parece que resolvi metade disso. Parece que
N = (K-sum(2**i for i in range(M)).bit_count()
em qualquer momento N<=M
. Isto parece ser porque,
K = sum(2**i for i in range(M)) + sum(2**(M-1-i) for i in range(N))
novamente, sempre que N<=M
. Parece que isso N<=M
ocorre cerca de metade das vezes.
length = 5
for K in range(2**length):
bits = bin(K)[2:].zfill(length)
M = K.bit_count() # numbers of "1"s in the binary sequence
N = sum(1 for i in range(K) if M==i.bit_count())
if N <= M:
A = sum(2**i for i in range(M)) + sum(2**(M-1-i) for i in range(N))
B = (K - sum(2**i for i in range(M))).bit_count()
else:
A = '-'
B = '-'
print(f'{K: <2}',bits,M,N,A,B)
Eu não conheço Python, então este é Ruby. O algoritmo deve ser fácil de traduzir. A ideia é, para cada bit definido (indo do menor para o maior), contar todos os números que são iguais à esquerda daquele bit, ter o mesmo número de bits definidos naquele bit e à sua direita, mas não tem esse pouco definido.
Código:
Resultados:
E para o seu grande exemplo:
A solução trivial:
No entanto, você pode tentar gerar apenas todos os números <
k
com uma contagem de bits específica e contá-los.Aqui está uma tentativa simples de fazer exatamente isso:
Isso funciona, mas é muito ineficiente, pois ainda precisa gerar todas as permutações que não são únicas. E no final, gerar uma permutação é muito mais lento do que apenas contar os bits.
Em vez disso, talvez seja melhor gerar combinações únicas de posições para zeros para números que possuem um certo número de unidades e depois calcular esses números:
No entanto, a solução ingénua utiliza operações que são tão eficientes que é mais eficiente apenas testar todos os números, em vez de descobrir quais devem ser evitados.
Tente executar isto:
Você descobrirá que
count_same0
é facilmente o mais rápido (na verdade, simplesmente rápido) e quecount_same2
é melhor quecount_same1
, mas não chega perto decount_same0
.Então acho que a resposta simples é realmente:
No entanto, para o seu valor de exemplo de
123456789123456789123456789
, isso levará muito tempo para ser concluído. Duvido que exista uma solução mais simples conhecida, visto que (depois de resolvê-la conforme descrito acima) também encontrei a sequência no OEIS: https://oeis.org/A079071 e basicamente define a mesma coisa. (e olhando o gráfico, não melhora muito: https://oeis.org/A079071/graph )Quem ou o que lhe encarregou de resolvê-lo por esse valor?
Expressando o número como uma combinação de bits e calculando o índice de combinação:
Saída (igual à de Dave):
Ah, droga, acabei de perceber que você está atrás de "uma fórmula simples". Ah bem. Talvez isso ainda seja útil para quem vem aqui em busca de código simples.