En un concurso de programación, se plantearon tres problemas que involucran diferentes áreas de la informática. A continuación, se presentan las soluciones técnicas para cada uno.
Problmea 1: Secuencia Recursiva con Módulo Pequeño
Se define una secuencia donde \( f[1]=f[2]=1 \) y \( f[n]=(A \times f[n-1] + B \times f[n-2]) \mod 7 \), con \( n \le 2^{31} \). La solución utiliza exponentiación rápida de matrices para calcular \( f[n] \) eficientemente. Debido al módulo pequeño, la secuencia puede exhibirr periodicidad, pero la implementación directa de matrices es robusta.
#include <bits/stdc++.h>
#define MOD 7
using namespace std;
typedef long long ll;
struct Matriz {
ll elementos[2][2];
Matriz() { memset(elementos, 0, sizeof(elementos)); }
Matriz operator*(const Matriz &otra) const {
Matriz resultado;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
for (int k = 0; k < 2; ++k)
resultado.elementos[i][k] = (resultado.elementos[i][k] + elementos[i][j] * otra.elementos[j][k]) % MOD;
return resultado;
}
};
Matriz potenciaRapida(Matriz base, ll exponente) {
Matriz identidad;
identidad.elementos[0][0] = identidad.elementos[1][1] = 1;
while (exponente) {
if (exponente & 1) identidad = identidad * base;
base = base * base;
exponente >>= 1;
}
return identidad;
}
int main() {
ll A, B, n;
cin >> A >> B >> n;
Matriz baseMatriz;
baseMatriz.elementos[0][0] = A;
baseMatriz.elementos[0][1] = 1;
baseMatriz.elementos[1][0] = B;
Matriz resultado = potenciaRapida(baseMatriz, n - 1);
cout << resultado.elementos[0][1] << endl;
return 0;
}
Problema 2: Combinatoria con Caminos Lattice
Dado \( T \) consultas con \( 0 \le n,m \le 20000 \), se busca el número de caminos desde \((0,0)\) a \((n,m)\) que no superen la diagonal \( y=x \). La solución formula es \( \frac{n-m+1}{n+1} \), derivada de la combinación de caminos en una cuadrícula, usando el principio de reflexión o identidades combinatorias. La implementación calcula directamente usando módulos inversos si es necesario.
#include <iostream>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
// Suponiendo cálculo modular para grandes valores, aquí se muestra la lógica esencial
double resultado = (double)(n - m + 1) / (n + 1);
cout << resultado << endl;
}
return 0;
}
Problema 3: Grafos con Componentes Biconectados y Diámetro de Árbol
Se tiene un grafo con \( n \) nodos y \( m \) aristas, y se pide la distancia máxima desde cada nodo a cualquier otro, considerando que dentro de una componente biconectada las aristas no teinen costo. La solución implica comprimir las componentes biconectadas usando el algoritmo de Tarjan, luego tratar el grafo resultante como un árbol y encontrar su diámetro. La distancia máxima para cada nodo se calcula como el máximo de las distancias a los dos extremos del diámetro.
#include <bits/stdc++.h>
#define MAXN 200100
#define INF 0x3f3f3f3f
using namespace std;
vector<pair<int,int>> grafoOriginal[MAXN], grafoComprimido[MAXN];
int bajo[MAXN], dfn[MAXN], contador, pila[MAXN], tope;
int componente[MAXN], tamanio[MAXN], etiquetaActual;
bool visitado[MAXN];
void tarjan(int u, int padre) {
bajo[u] = dfn[u] = ++contador;
pila[++tope] = u;
for (auto &[v, peso] : grafoOriginal[u]) {
if (!dfn[v]) {
tarjan(v, u);
bajo[u] = min(bajo[u], bajo[v]);
if (bajo[v] >= dfn[u]) {
++etiquetaActual;
int w;
do {
w = pila[tope--];
componente[w] = etiquetaActual;
++tamanio[etiquetaActual];
} while (w != v);
}
} else if (v != padre) {
bajo[u] = min(bajo[u], dfn[v]);
}
}
}
pair<int,int> dfsDiametro(int u, int padre, int distanciaActual, int &maxDistancia, int &extremo) {
if (distanciaActual > maxDistancia) {
maxDistancia = distanciaActual;
extremo = u;
}
for (auto &[v, peso] : grafoComprimido[u]) {
if (v != padre) {
dfsDiametro(v, u, distanciaActual + peso, maxDistancia, extremo);
}
}
return {maxDistancia, extremo};
}
int main() {
int n, m;
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int u, v, w;
cin >> u >> v >> w;
grafoOriginal[u].emplace_back(v, w);
grafoOriginal[v].emplace_back(u, w);
}
for (int i = 1; i <= n; ++i) if (!dfn[i]) tarjan(i, -1);
for (int u = 1; u <= n; ++u) {
for (auto &[v, peso] : grafoOriginal[u]) {
if (componente[u] != componente[v]) {
grafoComprimido[componente[u]].emplace_back(componente[v], peso);
}
}
}
int extremo1, extremo2, maxDist = -1;
dfsDiametro(1, -1, 0, maxDist, extremo1);
maxDist = -1;
dfsDiametro(extremo1, -1, 0, maxDist, extremo2);
// Calcular distancias desde ambos extremos del diámetro
vector<int> dist1(etiquetaActual + 1, -1), dist2(etiquetaActual + 1, -1);
// ... Implementación de BFS/DFS para distancias (omitida por brevedad)
for (int i = 1; i <= n; ++i) {
cout << max(dist1[componente[i]], dist2[componente[i]]) << endl;
}
return 0;
}