Durante el concurso, resolví el problema usando programación dinámica.
Primero, veamos la prueba de divisibilidad para 11. Un número es divisible por 11 si la suma de dígitos en posiciones impares y la suma de dígitos en posiciones pares difiere en un múltiplo de 11. Entonces, lo que debemos hacer es encontrar la cantidad de formas de dividir los dígitos del número original en dos partes de igual tamaño (o que difieran en una si la longitud original es impar) y permutando cada parte de tal manera que sus sumas difieran en un múltiplo de 11.
Para resolver esto usando programación dinámica, definamos primero algunas cantidades:
- L es la longitud del número original
- M es el número de dígitos en posiciones impares en el número. Si L es par, M = L / 2. De lo contrario M = (L + 1) / 2
- cnt [d] es el número de veces que el dígito d (0≤d≤9) aparece en el número original
- csum [d] es la suma de cnt [i] para d≤i≤9.
- DP [i] [j] [k] es el número de formas de formar dos cadenas usando los dígitos de i a 9, de modo que la primera cadena tiene j dígitos (y la segunda tiene csum [i] -j dígitos) y la diferencia entre las sumas de dígitos en las dos mitades deja el resto k en la división por 11.
Ahora, es fácil ver que DP [0] [M] [0] da la respuesta requerida. El caso base para nuestra recurrencia sería DP [10] [0] [0] = 1 y DP [10] [*] [*] = 0 de lo contrario. Veamos ahora la recurrencia exacta.
- Trigonometría (matemática): ¿Cómo puedo obtener un triple pitagórico de una hipotenusa dada (si existe)?
- ¿Cómo puedo generar 8 números (aleatorios) que deberían oscilar entre 0 y 80 y la suma de esos 8 números generados debería ser 80.?
- Combinatoria: Sea el conjunto de {(1,1), (1, -1), (-1,1)} -trayecto de red que comienza en (1,1), no use el mismo vértice dos veces, y nunca toque el eje x o el eje y. ¿Cuántos caminos terminan en el punto (4,8)?
- ¿Cómo puedo determinar el límite superior más ajustado para el problema 30 en el Proyecto Euler?
- ¿Cómo funciona la función isPerfect de esta solución, ya que el problema 29 del proyecto Euler está calculando el recuento?
Supongamos que hemos encontrado DP [i + 1] [*] [*]. ¿Cómo calculamos DP [i] [j] [k]? La primera cadena puede tener entre 0 y min (j, cnt [i]) ocurrencias del dígito i. Deje que el número exacto de ocurrencias sea p. Luego, al incluir el dígito i, se agrega p * i a la suma de dígitos en la primera mitad, y (cnt [i] -p) * i a la suma de dígitos en la segunda mitad. El recordatorio de la diferencia ha sido cambiado por q = (2 * p-cnt [i]) * i% 11. Deje j ‘= jp y k’ = kq. Antes de agregar todos los dígitos i, deberíamos haber estado en el estado DP [i + 1] [j ‘] [k’]. Dado que hay formas C (j, p) de colocar los pi en la primera cadena y formas C (csum [i] -j, cnt [i] -p) de colocar las i en la segunda cadena, la contribución a DP [i] [j] [k] es C (j, p) * C (csum [i] -j, cnt [i] -p) * DP [i + 1] [j ‘] [k’]. Resumiendo esto para todos los valores de p nos da DP [i] [j] [k].
Aquí está el pseudocódigo:
DP [11] [M + 1] [11] // Inicializado a 0 DP [10] [0] [0] = 1 para i = 9 a 0: para j = 0 a M: para k = 0 a 10: para p = 0 a min (j, cnt [i]): j '= jp k '= (ki * (2p-cnt [i]))% 11 if (i> 0) DP [i] [j] [k] + = C (j, p) * C (csum [i] -j, cnt [i] -p) * DP [i + 1] [j '] [k'] más DP [i] [j] [k] + = C (j-1, p) * C (csum [i] -j, cnt [i] -p) * DP [i + 1] [j '] [ k '] fin fin fin fin devolver DP [0] [M] [0]
La condición if hace el trabajo de evitar los ceros iniciales al restringir los ceros para que se coloquen solo en las posiciones restantes. En general, el ciclo se ejecuta menos de 100 * 50 * 11 veces, asegurando que la solución se termine dentro del límite de tiempo.