Solución de problemas del Codeforces Round 988 (Div. 3)

Problema A - Twice

Enunciado

Dada una secuencia de longitud \\(n\\), en cada operación se eligen dos índices \\(i, j\\). Si \\(a_i = a_j\\) y ninguno de los índices ha sido seleccionado previamente, la respuesta se incrementa en 1. Se debe determinar el valor máximo posible de la respuesta.

Enfoque

Simulación directa.

Solución

#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
using ll = long long;

bool usados[1000005];

void resolver() {
    int total, conteo = 0;
    cin >> total;
    memset(usados, 0, sizeof(usados));
    vector<int> datos(total);
    for (int idx = 0; idx < total; ++idx)
        cin >> datos[idx];
    
    for (int a = 0; a < total; ++a) {
        for (int b = a + 1; b < total; ++b) {
            if (datos[a] == datos[b] && !usados[a] && !usados[b]) {
                ++conteo;
                usados[a] = usados[b] = true;
            }
        }
    }
    cout << conteo << "\n";
}

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    int casos;
    cin >> casos;
    while (casos--) resolver();
    return 0;
}

Problema B - Intercepted Inputs

Enunciado

Se reciben \\(k\\) números enteros. Estos corresponden a la cantidad de elementos de una matriz \\(n \\times m\\) más los dos valores \\(n\\) y \\(m\\) mismos. Se debe encontrar cualquier par \\((n, m)\\) tal que \\(n \\times m + 2 = k\\) y ambos \\(n\\) y \\(m\\) aparezcan en la lista de entrada.

Enfoque

Se recorre la lista de números. Para cada número \\(v[i]\\), se verifica si \\(k-2\\) es divisible por \\(v[i]\\) y si el cociente ya ha sido visto anteriormente. Esto se puede implementar con un conjunto o un mapa de frecuencias.

Solución

#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
using ll = long long;

void resolver() {
    int cantidad;
    cin >> cantidad;
    vector<int> valores(cantidad);
    for (int i = 0; i < cantidad; ++i)
        cin >> valores[i];

    int objetivo = cantidad - 2;
    unordered_set<int> vistos;
    for (int elem : valores) {
        if (elem != 0 && objetivo % elem == 0) {
            int complemento = objetivo / elem;
            if (vistos.count(complemento)) {
                cout << elem << " " << complemento << "\n";
                return;
            }
        }
        vistos.insert(elem);
    }
}

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    int pruebas;
    cin >> pruebas;
    while (pruebas--) resolver();
    return 0;
}

Problema C - Superultra's Favorite Permutation

Enunciado

Dado un entero \\(n\\), construir una permutación de los números del 1 al \\(n\\) tal que la suma de cada par de elementos consecutivos sea un número compuesto. Si no existe tal permutación, se debe reportar -1.

Enfoque

Para \\(n \\le 4\\) no existe solución. La idea es separar números pares e impares, ya que la suma de dos pares o dos impares es siempre par y, por lo tanto, compuesta (excepto si es 2, pero eso no ocurre aquí). Luego, se coloca un par específico (como 4 y 5) en la unión para garantizar la condición de número compuesto.

Solución

#include <iostream>
using namespace std;
using ll = long long;

void resolver() {
    int n;
    cin >> n;
    if (n <= 4) {
        cout << -1 << "\n";
        return;
    }
    
    // Imprimir impares excepto 5
    for (int val = 1; val <= n; val += 2)
        if (val != 5) cout << val << " ";
    
    // Imprimir puente 5 y 4
    cout << 5 << " " << 4 << " ";
    
    // Imprimir pares excepto 4
    for (int val = 2; val <= n; val += 2)
        if (val != 4) cout << val << " ";
    
    cout << "\n";
}

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    int consultas;
    cin >> consultas;
    while (consultas--) resolver();
    return 0;
}

Problema D - Sharky Surfing

Enunciado

Existen \\(n\\) obstáculos, cada uno representado por un intervalo \\([l_i, r_i]\\). Para superar el obstáculo \\(i\\) se debe saltar desde \\(l_i - 1\\) hasta \\(r_i + 1\\). Hay \\(m\\) ítems en posiciones \\(x_j\\) que incrementan la capacidad de salto en \\(v_j\\). Comenzendo en la posición 1 con capacidad de salto 1, se quiere llegar a la posición \\(L\\). Se debe calcular el mínimo número de ítems necesarios o determinar que es imposible.

Enfoque

Se itera sobre los obstáculos en orden. Para cada obstáculo, se recogen todos los ítems que aparecen antes de su inicio. Se utiliza una cola de prioridad (o multiset) para almacenar las mejoras disponibles. Se toma repetidamente la mejora más grande hasta que la capacidad de salto supere la longitud del obstáculo actual. Si no es posible, se retorna -1.

Solución

#include <iostream>
#include <vector>
#include <queue>
#include <functional>
using namespace std;
using ll = long long;

void resolver() {
    int n, m, L;
    cin >> n >> m >> L;
    
    vector<pair<int,int>> bloqueos(n);
    for (auto & [l, r] : bloqueos) cin >> l >> r;
    
    vector<pair<int,int>> potenciadores(m);
    for (auto & [pos, val] : potenciadores) cin >> pos >> val;
    
    priority_queue<int> disponibles;
    int poder = 1, necesarios = 0, idxItem = 0;
    
    for (auto & [ini, fin] : bloqueos) {
        // Recolectar potenciadores antes del obstáculo
        while (idxItem < m && potenciadores[idxItem].first < ini) {
            disponibles.push(potenciadores[idxItem].second);
            ++idxItem;
        }
        
        // Necesitamos poder >= (fin - ini + 1) para saltar
        int requerido = fin - ini + 1;
        while (!disponibles.empty() && poder <= requerido) {
            poder += disponibles.top();
            disponibles.pop();
            ++necesarios;
        }
        
        if (poder <= requerido) {
            cout << -1 << "\n";
            return;
        }
    }
    
    cout << necesarios << "\n";
}

int main() {
    cin.tie(nullptr) -> sync_with_stdio(false);
    int pruebas;
    cin >> pruebas;
    while (pruebas--) resolver();
    return 0;
}

Etiquetas: codeforces greedy-algorithm number-theory Arrays sets

Publicado el 7-4 17:02