Digamos que tenhamos um número inteiro não negativo que seja "robusto" (ou seja, "pesado") se o valor médio do dígito for maior que 7.
O número 6959 é "robusto" porque:
(6 + 9 + 5 + 9) / 4 = 7,5
O número 1234 não é, porque:
(1 + 2 + 3 + 4) / 4 = 2,5
Escreva uma função, em qualquer idioma,
HeftyDecimalCount(a, b)
que, quando fornecidos dois números inteiros positivos aeb retorna um número inteiro indicando quantos números inteiros "pesados" estão dentro do intervalo [a..b], inclusive.
Por exemplo, dado a = 9480 eb = 9489:
9480 (9+4+8+0)/4 21/4 = 5.25
9481 (9+4+8+1)/4 22/4 = 5.5
9482 (9+4+8+2)/4 23/4 = 5.75
9483 (9+4+8+3)/4 24/4 = 6
9484 (9+4+8+4)/4 25/4 = 6.25
9485 (9+4+8+5)/4 26/4 = 6.5
9486 (9+4+8+6)/4 27/4 = 6.75
9487 (9+4+8+7)/4 28/4 = 7
9488 (9+4+8+8)/4 29/4 = 7.25 hefty
9489 (9+4+8+9)/4 30/4 = 7.5 hefty
Dois dos números nesse intervalo são "pesados" e, portanto, a função deve retornar 2.
Algumas diretrizes:
- suponha que nem a ou b exceda 200.000.000.
- uma solução n-quadrado funcionará, mas será lenta - qual é a velocidade mais rápida que podemos resolver?
Respostas:
O problema pode ser resolvido em O (polylog (b)).
Definimos
f(d, n)
como o número de inteiros de até d dígitos decimais com soma de dígitos menor ou igual a n. Pode-se ver que essa função é dada pela fórmulaUsando esta fórmula, podemos, por exemplo, encontrar o número de números pesados no intervalo de 8000 a 8999
1000 - f(3, 20)
, pois , porque existem milhares de números nesse intervalo, e temos que subtrair o número de números com soma de dígitos menor ou igual a 28 enquanto deduz que o primeiro dígito já contribui com 8 para a soma do dígito.Como um exemplo mais complexo, vejamos o número de números pesados no intervalo 1234..5678. Podemos primeiro ir de 1234 a 1240 nas etapas de 1. Em seguida, vamos de 1240 a 1300 nas etapas de 10. A fórmula acima nos fornece o número de números pesados em cada intervalo:
Agora vamos de 1300 a 2000 em etapas de 100:
De 2000 a 5000 em etapas de 1000:
Agora temos que reduzir o tamanho da etapa novamente, passando de 5000 para 5600 nas etapas de 100, de 5600 para 5670 nas etapas de 10 e, finalmente, de 5670 para 5678 nas etapas de 1.
Um exemplo de implementação do Python (que recebeu algumas otimizações e testes enquanto isso):
Editar : substituiu o código por uma versão otimizada (que parece ainda mais feia que o código original). Também consertei alguns casos de canto enquanto eu estava nisso.
heavy(1234, 100000000)
leva cerca de um milissegundo na minha máquina.fonte
binomial()
função. Há também mais algumas coisas que podem ser facilmente melhoradas. Vou postar uma atualização em alguns minutos.f(d, n)
não é chamado duas vezes com os mesmos parâmetros durante uma execução do programa.Recupere e use permutações.
Suponha que definamos uma função geral que encontre os valores entre aeb com um peso maior que x:
Com o seu exemplo de a = 8675 eb = 8689, o primeiro dígito é 8, então jogue-o fora - a resposta será igual a 675 a 689 e novamente de 75 a 89.
O peso médio dos dois primeiros dígitos 86 é 7, portanto os dígitos restantes precisam de um peso médio superior a 7 para se qualificar. Assim, a chamada
é equivalente a
Portanto, nosso alcance para o (novo) primeiro dígito é de 7 a 8, com estas possibilidades:
Para 7, ainda precisamos de uma média superior a 7, que só pode vir de um dígito final de 8 ou 9, fornecendo 2 valores possíveis.
Para 8, precisamos de uma média superior a 6, que só pode vir de um dígito final de 7-9, fornecendo 3 valores possíveis.
Assim, 2 + 3 produz 5 valores possíveis.
O que está acontecendo é que o algoritmo está começando com o número de 4 dígitos e dividindo-o em problemas menores. A função se chamaria repetidamente com versões mais fáceis do problema até que ele tenha algo com que possa lidar.
fonte
Talvez você possa pular muitos candidatos no intervalo de a para b acumulando seu "peso".
se você souber o comprimento do seu número, sabe que todos os dígitos podem alterar o peso em apenas 1 / comprimento.
Portanto, se você começar com um número que não é pesado, poderá calcular o próximo número que será pesado, se você os aumentar em um.
No exemplo acima, iniciando com 8680 avg = 5,5, que fica a 7-5,5 = 1,5 ponto da sua borda de peso, você saberia que existem 1,5 / (1/4) = 6 números no meio, que NÃO são pesados.
Isso deve ser o truque!
fonte
/length
.Que tal uma função recursiva simples? Para simplificar, calcula todos os números pesados com
digits
dígitos e uma soma mínima de dígitosmin_sum
.Implementou isso em python e encontrou todos os números pesados de 9 dígitos em ~ 2 segundos. Um pouco de programação dinâmica poderia melhorar isso.
fonte
Esta é uma solução possível.
fonte
C, para o intervalo [a, b] é O (ba)
//o exercício
//os resultados
fonte