#!/usr/bin/env python
# coding: utf-8
# # Recursión
#
# ## Definición
#
# La recursividad se puede definir como la capacidad de una función para construir su respuesta usándose a si misma. La RAE define ``recursivo`` de la siguiente manera:
#
#
Dicho especialmente de un proceso: Que se aplica de nuevo al resultado de haberlo aplicado previamente
#
# La recursión es una técnica de programación y matemática, se usa para problemas con la siguiente estructura: [Teoria](http://nbviewer.jupyter.org/github/ProgramacionCompetitivaUNI/ProgramacionCompetitivaUNI/blob/master/no-fiis/clase-09/clase-09.ipynb)
#
# 
#
# ## Recursión Matemática
#
# Toda recursión matemática debe estar compuesta por 2 elementos principales:
#
# - Conjunto de parámetros: Elementos con los cuales se trabaja para hallar la respuesta
# - Definición de la recursión: Proceso que se sigue para hallar la respuesta
#
# Inclusive, la **definición** de la recursión tiene 2 subelementos:
#
# - Casos base: Casos que ya no necesitan de la función para dar su respuesta
# - Predicado y recursión: Explicación de la función a resolver y la manera en cómo se logra hacerlo.
#
# Por ahora todo parece relativamente confuso, pero veamos el caso más simple de recursión: **El factorial**.
#
# La función factorial (que se expresa como "$x!$ se lee como factorial de x") está definida de la siguiente forma para los números enteros no negativos:
#
# $$ n! = \left\{ \begin{array}{cc} 1 &n=0 \\ n\cdot (n-1)! &\text{en otro caso} \\ \end{array} \right. $$
#
# En este caso, ``f(x) = x!`` (donde $x$ es el conjunto de parámetros), siendo $f(0) = 1$ como caso base y $f(n) = n\cdot f(n-1)$ nuestra recursión para $n \geq 1$. Además, a pesar de ser obvio, el predicado de $f$ es "$f(x)$ da como respuesta el producto de los numeros naturales entre el 1 y $x$".
#
#
# ### Las Torres de Hanoi
#
# Para introducir una manera un poco más formal de analizar las recursiones, veremos el conocido problema de las torres de hanoi, el cual señala lo siguiente:
#
# - Tenemos 3 postes fijos.
#
# - En uno de los postes hay 64 discos colocados con un tamaño descreciente desde la base hasta el tope.
#
# - En un movimiento, podemos llevar un disco del tope de alguno de los postes a otro poste que esté vacio o que el tamaño del primer disco de este sea mayor que el que moveremos.
#
# - El problema pide mover la torre de discos inicial y colocarlos de esa manera en otro poste.
#
# La idea es resolver este problema en la menor cantidad de tiempo posible, por lo que debemos determinar la mínima cantidad de movimientos posibles.
#
# Para resolver recursiones, siempre es bueno ver los casos pequeños para buscar un patrón. En este caso, vamos a generalizar: En vez de 64 discos, supongamos que hay $n$ discos.
#
# Entoncs, definimos la función $T(n)$ que nos dará la cantidad mínima de movimientos que se deben usar para resolver el problema con $n$ discos.
#
# Claramente, los casos más pequeños y lógicos serían:
#
# - $T(0) = 0$, no hay necesidad de movimientos si no hay discos
#
# - $T(1) = 1$, basta con colocar directamente el disco en el poste deseado
#
# - $T(2) = 3$, disco 1 -> poste 2, disco 2 -> poste 3, disco 1 -> poste 3
#
# Ahora, esta función poco a poco toma cierta forma, pero veamos matemáticamente los límites de la función $T$:
#
# Para mover $n$ discos a otro poste, por la naturaleza del problema, debemos mover la torre de $n-1$ discos superiores antes del $n$-ésimo disco a otro poste, luego movemos este disco al poste deseado y finalmente movemos los otros $n-1$ discos a la torre deseada. Esto se puede denotar como:
#
# $ T(n) \leq T(n-1) + 1 + T(n-1) $
#
# $ T(n) \leq 2T(n-1) + 1 $
#
# Ahora probamos el límite superior; pero si nos damos cuenta, la única situación en la que no se hacen movimientos innecesarios es la explicada anteriormente, pues necesitamos:
#
# 1) Al menos un poste esté libre
#
# 2) Salida sin problemas para el $n$-ésimo disco
#
# Por lo que esto se logra solamente si todos los otros $n-1$ discos están en un poste diferente al original, y por las condiciones, deben estar en forma de torre decreciente de la base al tope, entonces llegamos a que:
#
# $$ T(n) \geq T(n-1) + 1 + T(n-1) $$
#
# $$ T(n) \geq 2T(n-1) + 1 $$
#
# Juntando ambas desigualdades y el caso base $T(0)=0$, llegamos a que:
#
# $$ T(0) = 0 $$
#
#
#
# $$ T(n) = 2T(n-1)+1, n\geq 1 $$
#
# Esta recursión se ve similar a la función $f(n) = 2^{n}-1$, pero no estamos completamente seguros a menos que demostremos su veracidad. Probemos por inducción:
#
# 1) $T(0) = f(0) = 2^{0}-1 = 0$
#
# 2) $T(n) = f(n) = 2^{n}-1$
#
# 3) $T(n+1) = 2T(n) + 1 = 2(2^{n}-1)+1 = 2^{n+1}-2+1 = 2^{n+1}-1$ -> Probamos la igualdad de ambas funciones.
#
# Sin embargo, la meta de las recursiones no es adivinar la relación, sino ser más precisos y obtener conclusiones sin tener que jugar con nuestra suerte. Para evitar ello, plantearemos una manera más sencilla de analizar las recursiones separando por casos más adelante.
#
# ### Problema de Josephus
#
# Este problema señala que se colocarán $n$ personas en un círculo, de manera horaria, y en una ronda se eliminan cada 2 personas de las que están presentes. Se repiten las rondas hasta que solo quede una persona. Debemos determinar el número de la persona que queda.
#
# Una idea intuitiva, para empezar, es que la respuesta nunca será un número par, pues todos ellos son eliminados en la primera ronda.
#
# Definamos la función $J(n)$ como la que nos dará la respuesta para $n$ personas.
#
# Ahora, veamos los casos más pequeños:
#
# | n | 1 | 2 | 3 | 4 | 5 | 6 |
# |------|---|---|---|---|---|---|
# | J(n) | 1 | 1 | 3 | 1 | 3 | 5 |
#
# Ciertamente, no parece que haya un patrón estricto, tal vez es una repetición de 1 -> 1,3 -> 1,3,5 -> 1,3,5,7 -> ..., pero esto no nos ayuda a darle forma matemática al problema.
#
# Veamos el caso para $n=2k$:
#
# - Hay $2k$ personas inicialmente.
#
# - En la siguiente ronda han sido eliminadas todas las personas $2i$ y quedan las que tienen numeros $2i+1$.
#
# - Observación 1: La cantidad de personas ha sido reducida a $k$.
#
# - Observación 2: Ahora hay $k$ personas, pero sus números son 1,3,5,7,...,2i-1, por lo que la posición de la persona que se salva es igual a $J(k)$ pero su número para $J(2k)$ será $2J(k)-1$ por la biyección que se puede plantear.
#
# Con lo anterior, llegamos a que:
#
# $$ J(2k) = 2J(k)-1, k\geq 1 $$
#
# Ahora, supongamos $n=2k+1$:
#
# - Hay $2k+1$ personas inicialmente.
#
# - En la siguiente ronda han sido eliminadas todas las personas $2i$, pero con un paso más se elimina también la persona con número $1$ luego de la persona $2k$.
#
# - Observación 1: La cantidad de personas ha sido reducida a $k$.
#
# - Observación 2: Ahora hay $k$ personas, pero sus números son 3,5,7,...,2i+1, por lo que la posición de la persona que se salva es igual a $J(k)$, pero su número para $J(2k+1)$ será $2J(k)+1$.
#
# Con lo anterior, llegamos a que:
#
# $$ J(2k+1) = 2J(k)+1, k\geq 1 $$
#
# Entonces, con el caso base $J(1) = 1$ tenemos:
#
# $$ J(n) = \left\{ \begin{array}{cc} 1 &n=1 \\ 2J(k)-1 &n=2k, k > 0 \\ 2J(k)+1 &n=2k+1, k > 0 \end{array} \right. $$
#
#
# Aun no parece muy clara la recursión, veamos (ahora que nos es más sencillo) varios de los casos pequeños:
#
# | n | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
# |------|---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|
# | J(n) | 1 | 1 | 3 | 1 | 3 | 5 | 7 | 1 | 3 | 5 | 7 | 9 | 11 | 13 | 15 |
#
# Se ve claramente que se va tomando los primeros $2^{i}$ numeros impares y se repite el proceso aumentando $i$ en 1.
#
# Ahora, notemos que siempre la respuesta es 1 cuando $n = 2^{k}$, y por lo que nos hemos dado cuenta sobre las respuestas, el último número que no tendrá respuesta igual a 1 y que sea mayor que $n$ es precisamente $m=2^{k+1}-1$, pues para llegar al siguiente 1 aumentaríamos $2^{k}$, y basta con restar 1 para obtener el anterior. Entonces, se da la secuencia de los $2^{k}$ primeros números impares desde $n=2^{k}$ hasta $m=2^{k+1}-1$.
#
# Ahora, si nos damos cuenta, la secuencia de respuestas y sus parámetros están ordenadas, y además lo único que tienen diferente todos los números desde el $n$ hasta el $m$ son los bits hasta el de orden $k-1$. Ahora se nos puede ocurrir pensar en algo como que:
#
# Si $n = 2^{m} + l$, entonces su respuesta es la posición $l$ (con indexación desde 0) de los primeros impares, la cual sería $2l+1$, con $0 \leq l < 2^{m}$.
#
# Esto parece tener sentido debido al patrón y a nuestras observaciones, pero demostremos inductivamente que de verdad es la solución:
#
# - $J(1) = f(2^{0}+0) = 2(0)+1 = 1$.
#
# - $J(2^{m}+l) = 2l+1$.
#
# - Supongamos para $n=2^{m}+2k$ par:
#
# 1) $J(n) = 2J(\frac{n}{2})-1 = 2(2^{m-1}+k)-1 = 2(2k+1)-1 = 4k+1 = 2(2k)+1$, cumple cuando $l$ es par.
#
# - Supongamos para $n=2^{m}+2k+1$ impar:
#
# 1) $J(n) = 2J(\frac{n}{2})+1 = 2(2^{m-1}+k)+1 = 2(2k+1)+1 = 4k+3 = 2(2k+1)+1$, cumple cuando $l$ es impar.
#
#
# ### Problemas propuestos
#
# 1) ¿Cuál es la máxima cantidad de regiones que se pueden formar colocando $n$ rectas en un plano?
#
# 2) Igual que el problema 1, pero esta vez no son rectas, sino lineas infinitas en forma de zig-zag (Como una V rotada e infinita en extensión)
#
# 3) Halle la solución para las Torres de Hanoi pero si se da que los movimientos directamente del poste $A$ (original) al $C$ (deseado) no son válidos.
#
# ## Fractales
#
# Los fractales son estructuras matemáticas cuya construcción se define por una profundidad como parámetro y un proceso recursivo.
#
# Son un área de estudio relativamente reciente en las matemáticas, y por su comportamiento, inspira la curiosidad de muchas personas. Este caso no es diferente para programación competitiva, pues existen una cantidad considerable de problemas relacionados con estos.
#
# ### Copo de nieve de Koch
#
# 1) Se toma un segmento
#
# 2) Dividir cada segmento en 3 partes iguales, reemplazar la parte central por dos partes iguales formando un ángulo de 60 grados. Repetir hasta llegar a la profundidad deseada
#
# 
#
# Los problemas principalmente tratarán de construir un fractal dado su procedimiento o de intentar analizar cada uno de sus pasos.
#
# Veamos estos 4 problemas de recursión.
#
# - [Fit Squares in Triangle - Easy](https://www.codechef.com/problems/TRISQ)
#
# - [Fractal - Easy](http://www.spoj.com/problems/URJC2_F/)
#
# - [All Squares - Easy/Medium](https://uva.onlinejudge.org/index.php?option=onlinejudge&page=show_problem&problem=91)
#
# - [Connecting Soldiers - Medium](https://www.codechef.com/problems/NOKIA)
#
# ## Fast Exponentiation
#
# Esta es una manera de optimizar una exponenciación, la cual naturalmente se haría en $O(b)$ siendo $a$ la base y $b$ el exponente, para lograrla en $O(\log{b})$. La idea principalmente es barrer los bits de $b$:
#
# Supongamos que la representación binaria de $b$ es la siguiente:
#
# $$ b = b_{k}b_{k-1}\ldots b_{2}b_{1}b_{0} $$
#
# Entonces podemos representar:
#
# $$ a^{b} = a^{b_{k}\cdot2^{k} + b_{k-1}\cdot2^{k-1} + \ldots + 2\cdot b_{1} + b_{0}} $$
#
# Por lo cual podemos plantear lo siguiente:
#
# $$ a^{b} = a^{b_{0}}\cdot \left(a^{2}\right)^{b_{k}b_{k-1}\ldots b_{2}b_{1}} $$
#
# Entonces definimos la función $fast\_exp(a,b)$ como la que nos dará el resultado de $a^{b}$:
#
# $$ fast\_exp(a,b) = a^{b} $$
#
# Pero por lo que planteamos hace un momento, debemos ver el siguiente patrón:
#
# $$ fast\_exp(a,b) = a^{b mod 2} \cdot fast\_exp(a^{2},b/2) $$
#
# Donde $b/2$ es el cociente entero de la división de $b$ entre 2.
#
# De esta recursión, recordando además que $fast\_exp(a,0) = 1$, podemos plantear el siguiente código:
#
# ```Cpp
# long long fast_exp(long long a, int b){
# if(b == 0) return 1LL; // Caso base
# if(b % 2 == 0) return fast_exp(a*a,b/2); // Si el bit de orden 0 está apagado
# return a*fast_exp(a*a,b/2); // Si el bit de orden 0 esta prendido
# }
# ```
#
# Algo beneficioso de esta función es que se puede aplicar a cualquier operación que sea asociativa en repetición, como la suma, coseno de la suma de dos angulos, etc.
#
# ## Maximo Comun Divisor
#
# La idea instintiva para hallar el MCD de dos numeros $a$ y $b$ es iterar desde 1 hasta el minimo entre ambos y actualizar cada vez que encontramos un numero que divida a ambos, pero esto tiene una complejidad de $O(min(a,b))$, lo cual no es muy eficiente si usamos números hasta $10^{18}$. Para solucionar este problema, usaremos el algoritmo de Euclides, el cual usa la siguiente recusión (considerando $a \geq b$):
#
# $$ gcd(a,0) = a $$
# $$ gcd(a,b) = gcd(b,a mod b) $$
#
# Ahora, la veracidad del funcionamiento del algoritmo está demostrada, pero ¿Qué hay de su complejidad?.
#
# Para hallar un estimado de su complejidad debemos hallar lo que sucede en cada paso:
#
# $$ gcd(a,b) \rightarrow (a,b) $$
# $$ gcd(b,a mod b) \rightarrow (b,q),\text{ si } a = bk+q $$
#
# Y así se da de manera consecutiva. Sin embargo, notemos que el peor de los casos se debería dar cuando $a$ se reduce en lo mínimo posible; y al ser $a \geq b$, se da cuando $a = b+q$. De manera similar, $b = q+r$ y así consecutivamente. Si lo colocamos de una manera más fácil de ver, sería:
#
# Si fijamos la solución final:
#
# $$ 0 \rightarrow m \rightarrow n=m \rightarrow s=m+n \rightarrow \cdots \rightarrow b=q+r \rightarrow a=b+q $$
#
# Notamos que si colocamos la recursión de esta manera (tal que cada paso es tomar dos numeros consecutivos y colocarlos adecuadamente en los parámetros), se parece muchísimo a la sucessión de **Fibonacci**.
#
# Ciertamente, el peor de los casos se dará cuando $a$ y $b$ son números de Fibonacci consecutivos, en cuyo caso, si $a = F_{n}$ y $b = F_{n-1}$, la siguiente llamada a la función dará $a=F_{n-1}$ y $b=F_{n-2}$ como parámetros, realizando unas $n-1$ iteraciones con la función.
#
# Con lo anterior, tenemos que $gcd(F_{n},F_{n-1}) = \Theta(n)$ y para cualquier número $a$, $gcd(a,F_{n-1}) = O(n)$. Dado que $F_{n-1} = \Theta(\varphi^{n})$, esto implica aproximadamente que $gcd(a,b) = O(\log_{\varphi}{b})$ pero al ser $\varphi > 2$, entonces también se da que $gcd(a,b) = O(\log_{2}{b})$