Skip to Content

Milk Measurement

Análisis oficial (C++) 

Solución 1 - Mapa ordenado

Primero, como el número de mediciones es grande, las ordenamos por día. Cada vez que procesamos una medición, rastreamos la vaca cuya producción cambia, además de las producciones vieja y nueva. Después, comprobamos si las vacas con producción máxima cambiaron.

Para esto, hay que verificar varias condiciones. Por ejemplo, si el número de vacas con la producción máxima cambió, entonces el display hay que actualizarlo. Sin embargo, el número de vacas podría quedarse igual y aun así el display podría necesitar actualización.

Para comprobarlo, verificamos si la vaca actual estaba originalmente en el display, y si sigue ahí después de que cambia la medición.

Implementación

Complejidad temporal: O(NlogN)\mathcal{O}(N\log N)

#include <algorithm> #include <fstream> #include <iostream> #include <map> #include <vector> using std::cout; using std::endl; using std::vector; struct Log { int day, cow, change; }; int main() { std::ifstream read("measurement.in"); int n; int g; read >> n >> g; vector<Log> log(n); std::map<int, int> cows; for (Log &l : log) { read >> l.day >> l.cow >> l.change; cows[l.cow] = g; } std::sort(log.begin(), log.end(), [](const Log &l1, const Log &l2) { return l1.day < l2.day; }); std::map<int, int> milk_prod{{g, n}}; int change_amt = 0; for (Log l : log) { int milk_amt = cows[l.cow]; bool was_top = milk_amt == milk_prod.rbegin()->first; int prev_count = milk_prod[milk_amt]; // quitamos el número anterior de producción de leche milk_prod[milk_amt]--; if (milk_prod[milk_amt] == 0) { milk_prod.erase(milk_amt); } // actualizamos las cantidades de producción de leche milk_amt += l.change; cows[l.cow] = milk_amt; milk_prod[milk_amt]++; bool is_top = milk_amt == milk_prod.rbegin()->first; int curr_count = milk_prod[milk_amt]; if (was_top) { if (is_top && curr_count == prev_count) { continue; } /* * si era la más alta y ahora no lo es o ahora hay * varias vacas con el máximo, entonces FJ tiene que cambiar el retrato */ change_amt++; } else if (is_top) { /* * si no estaba en el máximo pero ahora sí, * entonces FJ también tiene que cambiar el retrato */ change_amt++; } } std::ofstream("measurement.out") << change_amt << endl; }
import java.io.*; import java.util.*; public class Measurement { // BeginCodeSnip{Log Class} private static class Log { int day, cow, change; public Log(int day, int cow, int change) { this.day = day; this.cow = cow; this.change = change; } } // EndCodeSnip public static void main(String[] args) throws IOException { Kattio io = new Kattio("measurement"); int n = io.nextInt(); int g = io.nextInt(); Log[] log = new Log[n]; Map<Integer, Integer> cows = new HashMap<>(); for (int i = 0; i < n; i++) { log[i] = new Log(io.nextInt(), io.nextInt(), io.nextInt()); cows.put(log[i].cow, g); } Arrays.sort(log, Comparator.comparingInt(o -> o.day)); // contiene la tabla de frecuencias de producción de leche en orden creciente TreeMap<Integer, Integer> milkProd = new TreeMap<>(); milkProd.put(g, n); int changeAmt = 0; for (Log l : log) { int milkAmt = cows.get(l.cow); boolean wasTop = milkAmt == milkProd.lastKey(); int prevCount = milkProd.get(milkAmt); // quitamos el número anterior de producción de leche milkProd.put(milkAmt, milkProd.get(milkAmt) - 1); if (milkProd.get(milkAmt) == 0) { milkProd.remove(milkAmt); } // actualizamos las cantidades de producción de leche milkAmt += l.change; cows.put(l.cow, milkAmt); milkProd.put(milkAmt, milkProd.getOrDefault(milkAmt, 0) + 1); boolean isTop = milkAmt == milkProd.lastKey(); int currCount = milkProd.get(milkAmt); if (wasTop) { if (isTop && currCount == prevCount) { continue; } /* * si era la más alta y ahora no lo es o ahora hay * varias vacas con el máximo, entonces FJ tiene que cambiar el retrato */ changeAmt++; } else if (isTop) { /* * si no estaba en el máximo pero ahora sí, * entonces FJ también tiene que cambiar el retrato */ changeAmt++; } } io.println(changeAmt); io.close(); } // CodeSnip{Kattio} }
import bisect with open("measurement.in", "r") as read: n, g = map(int, read.readline().split()) measurements = [list(map(int, read.readline().split())) for i in range(n)] # ordenamos por día measurements.sort() # mantenemos una lista ordenada y un diccionario de producciones de las vacas sorted_list = [] cows = list(set([x[1] for x in measurements])) values = dict() for i in range(len(cows)): values[cows[i]] = g sorted_list.append([g, cows[i]]) changes = 0 sorted_list.append([g, float("inf")]) top_cows = sorted(set(cows + [float("inf")])) for i in range(n): day, cow, change = map(int, measurements[i]) # hallamos el índice a actualizar usando bisect index = bisect.bisect_left(sorted_list, [values[cow], cow]) # mantenemos el orden ordenado sorted_list.pop(index) bisect.insort(sorted_list, [values[cow] + change, cow]) values[cow] += change # hallamos la producción más alta highest_output = sorted_list[-1][0] # hallamos las vacas con la producción más alta top_cows2 = [] for j in range(len(sorted_list) - 1, -1, -1): if sorted_list[j][0] == highest_output: top_cows2.append(sorted_list[j][1]) else: break top_cows2.sort() if top_cows != top_cows2: top_cows = top_cows2 changes += 1 print(changes, file=open("measurement.out", "w"))

Solución 2 - Cola de prioridad

Un método alternativo para llevar la cuenta de la producción máxima de leche es usar una cola de prioridad en vez de un mapa ordenado. Todos los mapas ordenados del código de la solución de arriba se pueden dejar como están o intercambiar por tablas hash.

Implementación

#include <algorithm> #include <cassert> #include <fstream> #include <iostream> #include <queue> #include <unordered_map> #include <vector> using std::endl; using std::vector; struct Log { int day, cow, change; }; int main() { std::ifstream read("measurement.in"); int n; int g; read >> n >> g; vector<Log> log(n); std::unordered_map<int, int> cows; // o std::map for (Log &l : log) { read >> l.day >> l.cow >> l.change; cows[l.cow] = g; } std::sort(log.begin(), log.end(), [](const Log &l1, const Log &l2) { return l1.day < l2.day; }); std::unordered_map<int, int> milk_prod{{g, n}}; std::priority_queue<int> possible_maxes; possible_maxes.push(g); auto query_max = [&]() -> int { while (true) { assert(!possible_maxes.empty()); if (milk_prod.count(possible_maxes.top())) break; possible_maxes.pop(); } return possible_maxes.top(); }; int change_amt = 0; for (Log l : log) { int milk_amt = cows[l.cow]; bool was_top = milk_amt == query_max(); int prev_count = milk_prod[milk_amt]; // quitamos el número anterior de producción de leche milk_prod[milk_amt]--; if (milk_prod[milk_amt] == 0) { milk_prod.erase(milk_amt); } // actualizamos las cantidades de producción de leche milk_amt += l.change; cows[l.cow] = milk_amt; milk_prod[milk_amt]++; possible_maxes.push(milk_amt); bool is_top = milk_amt == query_max(); int curr_count = milk_prod[milk_amt]; if (was_top) { if (is_top && curr_count == prev_count) { continue; } /* * si era la más alta y ahora no lo es o ahora hay * varias vacas con el máximo, entonces FJ tiene que cambiar el retrato */ change_amt++; } else if (is_top) { /* * si no estaba en el máximo pero ahora sí, * entonces FJ también tiene que cambiar el retrato */ change_amt++; } } std::ofstream("measurement.out") << change_amt << endl; }