Digamos que tenemos un número entero no negativo que es "fuerte" (es decir, "pesado") si su valor de dígito promedio es mayor que 7.
El número 6959 es "fuerte" porque:
(6 + 9 + 5 + 9) / 4 = 7.5
El número 1234 no es porque:
(1 + 2 + 3 + 4) / 4 = 2.5
Escribe una función, en cualquier idioma,
HeftyDecimalCount(a, b)
que, cuando se proporcionan dos enteros positivos a y b, devuelve un entero que indica cuántos enteros "fuertes" están dentro del intervalo [a..b], inclusive.
Por ejemplo, dado a = 9480 yb = 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
Dos de los números en este rango son "fuertes" y, por lo tanto, la función debería devolver 2.
Algunas pautas:
- supongamos que ni aob supera los 200,000,000.
- una solución de n cuadrado funcionará, pero será lenta: ¿cuál es la forma más rápida en que podemos resolver esto?
Respuestas:
El problema se puede resolver en O (polylog (b)).
Definimos
f(d, n)
como el número de enteros de hasta d dígitos decimales con una suma de dígitos menor o igual a n. Se puede ver que esta función viene dada por la fórmulaCon esta fórmula, por ejemplo, podemos encontrar el número de números pesados en el intervalo de 8000 a 8999
1000 - f(3, 20)
, ya que hay miles de números en este intervalo, y tenemos que restar el número de números con una suma de dígitos menor o igual a 28 mientras se cuenta que el primer dígito ya contribuye 8 a la suma de dígitos.Como un ejemplo más complejo, veamos el número de números pesados en el intervalo 1234..5678. Primero podemos pasar de 1234 a 1240 en pasos de 1. Luego pasamos de 1240 a 1300 en pasos de 10. La fórmula anterior nos da la cantidad de números pesados en cada intervalo:
Ahora vamos de 1300 a 2000 en pasos de 100:
De 2000 a 5000 en pasos de 1000:
Ahora tenemos que reducir el tamaño del paso nuevamente, pasando de 5000 a 5600 en pasos de 100, de 5600 a 5670 en pasos de 10 y finalmente de 5670 a 5678 en pasos de 1.
Un ejemplo de implementación de Python (que recibió ligeras optimizaciones y pruebas mientras tanto):
Editar : reemplazó el código por una versión optimizada (que se ve aún más fea que el código original). También arreglé algunos casos de esquina mientras estaba en eso.
heavy(1234, 100000000)
toma alrededor de un milisegundo en mi máquina.fuente
binomial()
función. También hay algunas cosas más que pueden mejorarse fácilmente. Publicaré una actualización en unos minutos.f(d, n)
lo general, no se llama dos veces con los mismos parámetros durante una ejecución del programa.Recurrir y usar permutaciones.
Supongamos que definimos una función general que encuentra los valores entre ayb con un peso mayor que x:
Con su ejemplo de a = 8675 a b = 8689, el primer dígito es 8, así que tírelo: la respuesta será la misma que 675 a 689, y nuevamente de 75 a 89.
El peso promedio de los primeros dos dígitos 86 es 7, por lo que los dígitos restantes necesitan un peso promedio de más de 7 para calificar. Por lo tanto, la llamada
es equivalente a
Por lo tanto, nuestro rango para el (nuevo) primer dígito es de 7 a 8, con estas posibilidades:
Para 7, todavía necesitamos un promedio de más de 7, que solo puede provenir de un dígito final de 8 o 9, lo que nos da 2 valores posibles.
Para 8, necesitamos un promedio de más de 6, que solo puede provenir de un dígito final de 7-9, lo que nos da 3 valores posibles.
Entonces, 2 + 3 produce 5 valores posibles.
Lo que sucede es que el algoritmo comienza con el número de 4 dígitos y lo divide en problemas más pequeños. La función se llamaría repetidamente con versiones más fáciles del problema hasta que tenga algo que pueda manejar.
fuente
Quizás pueda omitir muchos candidatos en el intervalo de a a b acumulando su "pesadez".
si conoce la longitud de su número, sabe que cada dígito puede cambiar la pesadez solo 1 / longitud.
Entonces, si comienzas en un número que no es pesado, deberías poder calcular el siguiente número que será pesado, si los aumentas en uno.
En su ejemplo anterior que comienza en 8680 avg = 5.5, que está a 7-5.5 = 1.5 puntos de distancia de su límite de pesadez, sabría que hay 1.5 / (1/4) = 6 números en el medio, que NO son pesados.
Eso debería ser el truco!
fuente
/length
.¿Qué tal una función recursiva simple? Para simplificar las cosas, calcula todos los números pesados con
digits
dígitos y una suma mínima de dígitos demin_sum
.Implementé esto en Python y encontró todos los números pesados de 9 dígitos en ~ 2 segundos. Un poco de programación dinámica podría mejorar esto.
fuente
Esta es una posible solución.
fuente
C, para el intervalo [a, b] es O (ba)
//el ejercicio
//Los resultados
fuente