🧩 Retos que molan
Estos problemas son más difíciles. No pasa nada si no te salen a la primera. De hecho, es normal. Usa las pistas, piensa, y si te atascas... ¡descansa y vuelve!
- Lee el problema e intenta resolverlo (15-20 min)
- Si te atascas, abre la Pista 1
- Sigue intentando. Si sigues atascado, abre más pistas
- Solo mira la solución cuando hayas agotado las pistas
🎯 Reto 1: El Cifrado Secreto (8 pts)
Importante: Los espacios y signos de puntuación no cambian. Las mayúsculas siguen siendo mayúsculas.
Entrada:
Krod Pxqgr
3
Salida:
Hola Mundo
Explicación: Cada letra se desplazó 3 posiciones. K→H, r→o, o→l, d→a...
💡 Pista 1: ¿Por dónde empiezo?
Piensa letra por letra. Para cada carácter:
- Si es letra → desplázala hacia atrás N posiciones
- Si no es letra → déjala igual
¿Cómo saber si es letra? → .isalpha()
💡 Pista 2: ¿Cómo desplazo una letra?
Las letras tienen un número asociado (código ASCII):
ord('A')→ 65ord('a')→ 97chr(65)→ 'A'
Para desplazar: convierte a número, resta N, convierte a letra.
💡 Pista 3: ¿Y si me paso del alfabeto?
Si la letra es 'A' y restas 3, te pasas. Necesitas "dar la vuelta" al alfabeto.
El truco: usa módulo 26 (hay 26 letras).
posicion = (ord(letra) - ord('A') - n) % 26
nueva_letra = chr(posicion + ord('A'))
💡 Pista 4: Mayúsculas y minúsculas
Usa .isupper() para saber si es mayúscula.
Si es mayúscula, usa ord('A') como base.
Si es minúscula, usa ord('a') como base.
🍌 Ver solución Minion (paso a paso)
# Leer el mensaje cifrado y el desplazamiento
mensaje = input()
n = int(input())
# Crear el alfabeto para referencia
alfabeto_mayus = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
alfabeto_minus = "abcdefghijklmnopqrstuvwxyz"
resultado = ""
# Procesar cada carácter
for letra in mensaje:
if letra in alfabeto_mayus:
# Es mayúscula
posicion_actual = alfabeto_mayus.index(letra)
nueva_posicion = (posicion_actual - n) % 26
nueva_letra = alfabeto_mayus[nueva_posicion]
resultado = resultado + nueva_letra
elif letra in alfabeto_minus:
# Es minúscula
posicion_actual = alfabeto_minus.index(letra)
nueva_posicion = (posicion_actual - n) % 26
nueva_letra = alfabeto_minus[nueva_posicion]
resultado = resultado + nueva_letra
else:
# No es letra, dejar igual
resultado = resultado + letra
print(resultado)
😎 Ver solución Gru (compacta)
mensaje = input()
n = int(input())
resultado = ""
for c in mensaje:
if c.isalpha():
base = ord('A') if c.isupper() else ord('a')
resultado += chr((ord(c) - base - n) % 26 + base)
else:
resultado += c
print(resultado)
ord() y chr() convierten letra↔número. El % 26 hace la "vuelta" automática.🎯 Reto 2: El Medallero (10 pts)
- Más oros (de mayor a menor)
- Si empatan en oros → más platas
- Si empatan en platas → más bronces
- Si empatan en todo → orden alfabético del país
Entrada:
4
España 3 5 2
Francia 3 5 2
Italia 4 1 1
Alemania 3 4 5
Salida:
Italia
España
Francia
Alemania
Italia tiene más oros. España y Francia empatan en todo, así que van por orden alfabético.
💡 Pista 1: ¿Cómo guardo los datos?
Una lista de tuplas o listas:
paises = []
paises.append(("España", 3, 5, 2))
paises.append(("Francia", 3, 5, 2))
...
💡 Pista 2: ¿Cómo ordeno por varios criterios?
La función sorted() acepta una key que puede devolver una tupla.
Python compara tuplas elemento por elemento:
(3, 5) < (4, 1) # False, porque 3 < 4
(3, 5) < (3, 6) # True, empatan en el primero, 5 < 6
💡 Pista 3: Orden descendente en unos, ascendente en otros
Truco: para ordenar de mayor a menor, usa números negativos.
# Ordenar por edad descendente
sorted(personas, key=lambda x: -x.edad)
# Ordenar por edad desc, nombre asc
sorted(personas, key=lambda x: (-x.edad, x.nombre))
🍌 Ver solución Minion (paso a paso)
# Leer número de países
n = int(input())
# Guardar los datos de cada país
paises = []
for i in range(n):
linea = input()
partes = linea.split()
nombre = partes[0]
oros = int(partes[1])
platas = int(partes[2])
bronces = int(partes[3])
paises.append([nombre, oros, platas, bronces])
# Ordenar con bubble sort (fácil de entender)
for i in range(len(paises)):
for j in range(i + 1, len(paises)):
pais_a = paises[i]
pais_b = paises[j]
# ¿Hay que intercambiar?
intercambiar = False
# Comparar por oros (más es mejor)
if pais_b[1] > pais_a[1]:
intercambiar = True
elif pais_b[1] == pais_a[1]:
# Empate en oros, comparar platas
if pais_b[2] > pais_a[2]:
intercambiar = True
elif pais_b[2] == pais_a[2]:
# Empate en platas, comparar bronces
if pais_b[3] > pais_a[3]:
intercambiar = True
elif pais_b[3] == pais_a[3]:
# Empate total, ordenar por nombre (A antes que Z)
if pais_b[0] < pais_a[0]:
intercambiar = True
if intercambiar:
paises[i] = pais_b
paises[j] = pais_a
# Imprimir solo los nombres
for pais in paises:
print(pais[0])
😎 Ver solución Gru (compacta)
n = int(input())
paises = []
for _ in range(n):
p = input().split()
paises.append((p[0], int(p[1]), int(p[2]), int(p[3])))
for pais in sorted(paises, key=lambda x: (-x[1], -x[2], -x[3], x[0])):
print(pais[0])
sorted() con tupla de criterios: negativo = descendente. Una línea hace todo el trabajo.🎯 Reto 3: Paréntesis Balanceados (7 pts)
(), corchetes [] y llaves {},
determina si están correctamente balanceados.
Entrada: {[()]}
Salida: SI
Entrada: {[(])}
Salida: NO
Entrada: ((())
Salida: NO
💡 Pista 1: ¿Qué estructura de datos necesito?
Piensa en una pila (stack). Es como una torre de platos:
- Solo puedes poner platos arriba (push)
- Solo puedes quitar el de arriba (pop)
En Python, una lista funciona como pila: append() y pop()
💡 Pista 2: ¿Cuál es la lógica?
Recorre la expresión carácter a carácter:
- Si es
(,[o{→ añádelo a la pila - Si es
),]o}→ saca el último de la pila y comprueba que coincidan
Al final, la pila debe estar vacía.
💡 Pista 3: ¿Cómo emparejar aperturas y cierres?
Usa un diccionario para saber qué cierre corresponde a cada apertura:
parejas = {'(': ')', '[': ']', '{': '}'}
🍌 Ver solución Minion (paso a paso)
expresion = input()
# Lista que usaremos como pila
pila = []
# Definir qué cierre corresponde a cada apertura
aperturas = "([{"
cierres = ")]}"
# Variable para saber si está balanceado
esta_bien = True
# Recorrer cada carácter
for caracter in expresion:
# ¿Es una apertura?
if caracter == "(" or caracter == "[" or caracter == "{":
pila.append(caracter)
# ¿Es un cierre?
elif caracter == ")" or caracter == "]" or caracter == "}":
# ¿Hay algo en la pila?
if len(pila) == 0:
esta_bien = False
break
# Sacar el último de la pila
ultimo = pila.pop()
# ¿Coinciden?
if caracter == ")" and ultimo != "(":
esta_bien = False
break
if caracter == "]" and ultimo != "[":
esta_bien = False
break
if caracter == "}" and ultimo != "{":
esta_bien = False
break
# Al final, la pila debe estar vacía
if len(pila) > 0:
esta_bien = False
if esta_bien:
print("SI")
else:
print("NO")
😎 Ver solución Gru (compacta)
exp = input()
parejas = {'(':')', '[':']', '{':'}'}
pila = []
ok = True
for c in exp:
if c in parejas: pila.append(c)
elif c in ')]}':
if not pila or parejas[pila.pop()] != c: ok = False; break
print("SI" if ok and not pila else "NO")
pila.pop() saca Y devuelve en una sola operación.🎯 Reto 4: Números Romanos (12 pts)
I=1, V=5, X=10, L=50, C=100, D=500, M=1000
Regla especial: Si un símbolo menor está antes de uno mayor, se resta (IV = 4, IX = 9, XL = 40...).
Entrada: MCMXCIV
Salida: 1994
(M=1000, CM=900, XC=90, IV=4 → 1000+900+90+4 = 1994)
💡 Pista 1: El patrón clave
Recorre de izquierda a derecha. Para cada símbolo:
- Si el siguiente símbolo es MAYOR → resta el actual
- Si no → suma el actual
💡 Pista 2: Guarda los valores en un diccionario
valores = {
'I': 1, 'V': 5, 'X': 10,
'L': 50, 'C': 100,
'D': 500, 'M': 1000
}
💡 Pista 3: Cómo mirar el siguiente
Usa un índice y compara con el siguiente:
for i in range(len(romano)):
actual = valores[romano[i]]
if i + 1 < len(romano):
siguiente = valores[romano[i + 1]]
# comparar...
🍌 Ver solución Minion (paso a paso)
# Leer el número romano
romano = input()
# Diccionario con el valor de cada símbolo
valores = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
total = 0
# Recorrer cada posición
for i in range(len(romano)):
simbolo_actual = romano[i]
valor_actual = valores[simbolo_actual]
# ¿Hay un símbolo después?
if i + 1 < len(romano):
simbolo_siguiente = romano[i + 1]
valor_siguiente = valores[simbolo_siguiente]
# Si el siguiente es mayor, hay que restar (ej: IV = 4)
if valor_siguiente > valor_actual:
total = total - valor_actual
else:
total = total + valor_actual
else:
# Es el último, solo sumar
total = total + valor_actual
print(total)
😎 Ver solución Gru (compacta)
romano = input()
v = {'I':1, 'V':5, 'X':10, 'L':50, 'C':100, 'D':500, 'M':10000
for i in range(len(romano)):
t += -v[romano[i]] if i+1 < len(romano) and v[romano[i]] < v[romano[i+1]] else v[romano[i]]
print(t)
🎯 Reto 5: Subsecuencia Creciente Más Larga (15 pts)
Una subsecuencia no tiene que ser consecutiva, pero debe mantener el orden original.
Entrada: 10 9 2 5 3 7 101 18
Salida: 4
(La subsecuencia es [2, 3, 7, 101] o [2, 5, 7, 101])
💡 Pista 1: Piensa en cada posición
Para cada número, pregúntate: ¿cuál es la subsecuencia creciente más larga que TERMINA en este número?
Al principio, cada número por sí solo tiene longitud 1.
💡 Pista 2: Mira hacia atrás
Para cada posición i, mira todas las posiciones anteriores j (donde j < i).
Si nums[j] < nums[i], entonces puedes "extender" la subsecuencia que terminaba en j.
💡 Pista 3: Programación dinámica básica
Crea una lista dp donde dp[i] = longitud de la subsecuencia más larga que termina en i.
dp = [1] * n # Todos empiezan en 1
for i in range(n):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[i], dp[j] + 1)
🍌 Ver solución Minion (paso a paso)
# Leer los números
linea = input()
partes = linea.split()
nums = []
for p in partes:
nums.append(int(p))
n = len(nums)
if n == 0:
print(0)
else:
# dp[i] = longitud de la subsecuencia más larga que TERMINA en posición i
# Al principio, cada número solo tiene longitud 1
dp = []
for i in range(n):
dp.append(1)
# Para cada posición...
for i in range(1, n):
# Miramos todas las posiciones anteriores
for j in range(i):
# Si el número en j es menor que en i, podemos extender
if nums[j] < nums[i]:
# ¿Es mejor extender desde j que lo que ya tenemos?
nueva_longitud = dp[j] + 1
if nueva_longitud > dp[i]:
dp[i] = nueva_longitud
# La respuesta es el máximo de todos los dp
respuesta = dp[0]
for valor in dp:
if valor > respuesta:
respuesta = valor
print(respuesta)
😎 Ver solución Gru (compacta)
nums = list(map(int, input().split()))
n = len(nums)
if n == 0: print(0)
else:
dp = [1] * n
for i in range(1, n):
for j in range(i):
if nums[j] < nums[i]: dp[i] = max(dp[i], dp[j] + 1)
print(max(dp))
dp[i] guarda el mejor resultado hasta i. El doble bucle compara con todos los anteriores.🎯 Reto 6: El Laberinto de Letras (10 pts)
Entrada:
3 4
ABCE
SFCS
ADEE
SEE
Salida: SI
(La palabra SEE se puede formar: S(1,0) → E(2,3) → E(2,2)... ¡espera, hay que repensar!
En realidad: S(1,0) → E(1,3)? No, mejor buscar camino válido)
💡 Pista 1: Divide el problema
Dos partes:
- Encontrar dónde puede empezar la palabra (todas las casillas con la primera letra)
- Desde cada inicio, intentar construir el resto de la palabra
💡 Pista 2: Búsqueda recursiva (backtracking)
Crea una función que reciba: posición actual, índice de la letra que buscamos.
Para cada vecino válido (arriba, abajo, izquierda, derecha), si tiene la letra correcta, llama recursivamente.
Si llegas al final de la palabra → ¡encontrado!
💡 Pista 3: Marcar casillas visitadas
Para no repetir casillas, márcalas temporalmente:
# Marcar como visitada
temp = grid[fila][col]
grid[fila][col] = '#'
# Explorar...
# Desmarcar (backtrack)
grid[fila][col] = temp
🍌 Ver solución Minion (paso a paso)
# Leer dimensiones de la cuadrícula
linea = input().split()
filas = int(linea[0])
cols = int(linea[1])
# Leer la cuadrícula
grid = []
for i in range(filas):
fila = list(input()) # Convertir string a lista de letras
grid.append(fila)
# Leer la palabra a buscar
palabra = input()
# Función para buscar desde una posición
def buscar(fila, col, indice_letra):
# Si ya encontramos toda la palabra, éxito!
if indice_letra == len(palabra):
return True
# ¿Estamos fuera de la cuadrícula?
if fila < 0 or fila >= filas:
return False
if col < 0 or col >= cols:
return False
# ¿La letra coincide?
if grid[fila][col] != palabra[indice_letra]:
return False
# Marcar como visitada (para no volver a pasar)
letra_guardada = grid[fila][col]
grid[fila][col] = '#'
# Intentar moverse en las 4 direcciones
encontrado = False
# Arriba
if buscar(fila - 1, col, indice_letra + 1):
encontrado = True
# Abajo
if not encontrado and buscar(fila + 1, col, indice_letra + 1):
encontrado = True
# Izquierda
if not encontrado and buscar(fila, col - 1, indice_letra + 1):
encontrado = True
# Derecha
if not encontrado and buscar(fila, col + 1, indice_letra + 1):
encontrado = True
# Desmarcar (backtrack) para probar otros caminos
grid[fila][col] = letra_guardada
return encontrado
# Probar desde cada casilla de la cuadrícula
resultado = False
for i in range(filas):
for j in range(cols):
if buscar(i, j, 0):
resultado = True
break
if resultado:
break
if resultado:
print("SI")
else:
print("NO")
😎 Ver solución Gru (compacta)
filas, cols = map(int, input().split())
grid = [list(input()) for _ in range(filas)]
palabra = input()
def buscar(f, c, idx):
if idx == len(palabra): return True
if f < 0 or f >= filas or c < 0 or c >= cols: return False
if grid[f][c] != palabra[idx]: return False
temp, grid[f][c] = grid[f][c], '#'
ok = buscar(f+1,c,idx+1) or buscar(f-1,c,idx+1) or buscar(f,c+1,idx+1) or buscar(f,c-1,idx+1)
grid[f][c] = temp
return ok
print("SI" if any(buscar(i,j,0) for i in range(filas) for j in range(cols)) else "NO")
any() con generador prueba todas las casillas.Si has intentado todos estos retos, aunque no los hayas resuelto todos, ya estás por encima del 90% de participantes en cualquier competición.
Cada problema "imposible" que intentas te hace mejor programador. El secreto no es ser un genio, es no rendirse.