Digamos que você tenha um dado de 20 lados. Você começa a rolar esse dado e precisa rolar algumas dezenas de vezes antes de finalmente rolar todos os 20 valores. Você quer saber, quantos rolos eu preciso antes de ter 50% de chance de ver todos os 20 valores? E quantos rolos de n
matriz de um lado eu preciso rolar antes de rolar por todos os n
lados?
Após algumas pesquisas, você descobre que existe uma fórmula para calcular a chance de rolar todos os n
valores após as r
rolagens.
P(r, n) = n! * S(r, n) / n**r
onde S(a, b)
denota números Stirling do segundo tipo , o número de maneiras de particionar um conjunto de n objetos (cada rolo) em k subconjuntos não vazios (cada lado).
Você também encontra a sequência OEIS , que chamaremos de R(n)
, que corresponde à menor r
em P(r, n)
pelo menos 50%. O desafio é calcular o n
termo th desta sequência o mais rápido possível.
O desafio
- Dado um
n
, encontre o menorr
ondeP(r, n)
é maior ou igual a0.5
ou 50%. - Teoricamente, seu código deve manipular qualquer número inteiro não negativo
n
como entrada, mas apenas testaremos seu código no intervalo de1 <= n <= 1000000
. - Para pontuação, estaremos tomar o tempo total necessário para executar
R(n)
em entradas1
através10000
. - Verificaremos se suas soluções estão corretas executando nossa versão de
R(n)
em sua saída para ver seP(your_output, n) >= 0.5
eP(your_output - 1, n) < 0.5
, ou seja, se sua saída é realmente a menorr
para um dadon
. - Você pode usar qualquer definição para
S(a, b)
em sua solução. A Wikipedia possui várias definições que podem ser úteis aqui. - Você pode usar built-ins em suas soluções, incluindo aquelas que calculam
S(a, b)
, ou mesmo aquelas que calculamP(r, n)
diretamente. - Você pode codificar até 1000 valores
R(n)
e um milhão de números Stirling, embora nenhum deles seja um limite rígido, e poderá ser alterado se você puder argumentar de maneira convincente para aumentá-los ou diminuí-los. - Você não precisa verificar todos os possíveis
r
entren
e or
que estamos procurando, mas precisa encontrar o menorr
e não apenasr
ondeP(r, n) >= 0.5
. - Seu programa deve usar um idioma que possa ser executado livremente no Windows 10.
As especificações do computador que testará suas soluções são i7 4790k, 8 GB RAM
. Agradecemos a @DJMcMayhem por fornecer seu computador para os testes. Sinta-se à vontade para adicionar seu próprio tempo não oficial para referência, mas o tempo oficial será fornecido mais tarde quando o DJ puder testá-lo.
Casos de teste
n R(n)
1 1
2 2
3 5
4 7
5 10
6 13
20 67 # our 20-sided die
52 225 # how many cards from a huge uniformly random pile until we get a full deck
100 497
366 2294 # number of people for to get 366 distinct birthdays
1000 7274
2000 15934
5000 44418
10000 95768
100000 1187943
1000000 14182022
Entre em contato se tiver alguma dúvida ou sugestão. Boa sorte e boa otimização!
fonte
Respostas:
Python + NumPy, 3,95 segundos
Experimente online!
Como funciona
Isso usa a série de forma fechada para P ( r , n ) e sua derivada em relação a r , reorganizada para estabilidade numérica e vetorização, para fazer uma pesquisa de método de Newton por r de modo que P ( r , n ) = 0,5, arredondando r para um número inteiro antes de cada etapa, até que a etapa se mova r em menos de 3/4. Com um bom palpite inicial, isso geralmente leva apenas uma ou duas iterações.
x i = log (1 - i / n ) = log (( n - i ) / n )
cx i = log ( n ! / (( n - i - 1)! ⋅ n i + 1 )
y i = cx i + cx n - i - 2 - cx n - 1 = log binom ( n , i + 1)
z i = (-1) i + 1 binom ( n ,i + 1) ⋅ (( n - i - 1) / n ) r
1 + ∑ z i = n! ⋅ S ( r , N ) / N r = P ( r , N )
z i ⋅ x i + 1 = (-1) i + 1 ⋅ binom ( n , i + 1) ⋅ (( n - i - 1) / n ) r log (( n - i - 1) / n)
Σ z i ⋅ x i + 1 = d / d r P ( r , N )
fonte
0.366512
eralog
algo de eras atrás. Usará-log(log(2)
na minha próxima iteração. Segundo, a idéia de usar o método de Newton também é muito inteligente e fico feliz em ver que isso funciona tão bem. Terceiro, eu definitivamente vou roubarexp(log(binom(n, i+1)) + r * log((n-i-1)/n))
: P Parabéns por uma ótima resposta! : Dnumpy
importação parafrom numpy import *
e, por algum motivo, o tempo caiu para basicamente 0 ... Experimente online ?r
, pois sua aproximação inicial já é bastante boa. Espero vê-lo no PPCG mais uma vez e desculpe por tudo.