Skip to Content

Balloons

Análisis oficial 

Explicación

El problema se puede resolver por simulación. En particular, queremos inflar los globos de izquierda a derecha. La parte difícil es determinar cuándo el nuevo globo bb toca alguno de los globos inflados aa a su izquierda, y cómo comprobar esto de forma eficiente para todos los globos inflados anteriores. Como notación, ara_r es el radio y axa_x la coordenada x del globo aa.

Primero, determinemos cuándo dos globos se “tocan” calculando el radio máximo del segundo globo brb_r. Como la coordenada x del globo inflado anterior axa_x y su radio ara_r están fijos, podemos construir un triángulo rectángulo con el centro de ambos globos de modo que los catetos sean paralelos a los ejes. Usando el teorema de Pitágoras, obtenemos (bxax)2+(brar)2=(br+ar)2(b_x - a_x)^2 + (b_r - a_r)^2 = (b_r + a_r)^2. Con un poco de álgebra, podemos obtener una expresión para el radio máximo del segundo globo br=(bxax)24arb_r = \frac{(b_x - a_x)^2}{4a_r}. Esto nos dice que el globo bb nunca puede tener un radio mayor que brb_r.

Con esta información, podríamos simplemente revisar cada globo inflado anterior y determinar cuál es el radio máximo de nuestro globo actual. Esto, sin embargo, tiene complejidad temporal O(n2)\mathcal{O}(n^2), que es demasiado lento. En su lugar, usamos la observación de que cualquier globo ii con irbri_r \leq b_r e ix<bxi_x < b_x nunca será tocado por globos posteriores a bb. Por lo tanto, guardamos los globos inflados en una pila. Cada vez que queremos inflar un nuevo globo bb, comprobamos cuánto puede ser el radio de bb bajo la restricción del primer elemento aa de la pila. (Por supuesto, brb_r debe seguir siendo menor que el máximo dado rr.) Si brarb_r \geq a_r, sacamos aa de la pila y comprobamos el siguiente elemento. aa no se volverá a comprobar. En caso contrario, si br<arb_r < a_r, podemos detener la comprobación y guardar nuestro globo recién inflado bb en esta pila.

Como quitamos el elemento de la pila una vez que queremos revisar más atrás, tenemos complejidad temporal O(n)\mathcal{O}(n).

Implementación

#include <bits/stdc++.h> using namespace std; const int PRECISION = 3; /* * how long can the radius of the new balloon at position bx be * so that it touches the ballon a, which is described by * its x position a.first and its radius a.second */ double calc_r(pair<double, double> a, double bx) { return (a.first - bx) * (a.first - bx) / (4 * a.second); } int main() { int n; cin >> n; // the radius of each balloon after inflating vector<double> final_radius(n); // the balloons we should check when we add a new one stack<pair<double, double>> to_check; for (int i = 0; i < n; i++) { double x, r; cin >> x >> r; // the maximum radius of the current balloon double max_r = r; /* * as long as the stack is not empty, we want to check * if the last balloon makes the radius of the current balloon smaller */ while (!to_check.empty()) { pair<double, double> last = to_check.top(); // the radius if the current balloon touches the last balloon double to_last_r = calc_r(last, x); /* * the maximum possible radius is the smaller one between current * maximum and the maximum radius so that we touches the last * balloon (by which we have to stop) */ max_r = min(max_r, to_last_r); /* * if current maximum radius >= radius of the last balloon, we can * remove the last balloon since it will never be touched by any * new balloons other than the current one */ if (max_r >= last.second) { to_check.pop(); // check the next balloon saved which will possibly reduce max_r continue; } /* * otherwise, the current balloon is smaller than the last saved * balloon and we can stop checking */ else { break; } } /* * save the x coordinate and radius of the current balloon, so that * it can be checked later when a new balloon being inflated */ to_check.push({x, max_r}); final_radius[i] = max_r; } cout << fixed << setprecision(PRECISION); for (double &r : final_radius) { cout << r << "\n"; } }

Implementación

import java.io.*; import java.util.*; // class Balloons causes compilation error on ojuz, and therefore bal public class bal { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); // the radius of each balloon after inflating double[] finalRadius = new double[n]; // the balloons we should check when we add a new one Stack<Balloon> toCheck = new Stack<>(); for (int i = 0; i < n; i++) { StringTokenizer st = new StringTokenizer(br.readLine()); long x = Integer.parseInt(st.nextToken()); double r = Integer.parseInt(st.nextToken()); // the maximum radius of the current balloon double maxR = r; /* * as long as the stack is not empty, we want to check * if the last balloon makes the radius of the current balloon * smaller */ while (!toCheck.isEmpty()) { // the radius if the current balloon touches the last balloon double toLastR = toCheck.peek().calcR(x); /* * the maximum possible radius is the smaller one between * current maximum and the maximum radius so that we touches the * last balloon (by which we have to stop) */ maxR = Math.min(maxR, toLastR); /* * if current maximum radius >= radius of the last balloon, we * can remove the last balloon since it will never be touched by * any new balloons other than the current one */ if (maxR >= toCheck.peek().r) { toCheck.pop(); // check the next balloon saved which will possibly reduce // max_r continue; } /* * otherwise, the current balloon is smaller than the last saved * balloon and we can stop checking */ else { break; } } /* * save the x coordinate and radius of the current balloon, so that * it can be checked later when a new balloon being inflated */ toCheck.add(new Balloon(x, maxR)); finalRadius[i] = maxR; } PrintWriter pw = new PrintWriter(System.out); for (double r : finalRadius) { pw.println(r); } pw.close(); } // class to save the data of an inflated balloon private static class Balloon { public long x; public double r; public Balloon(long x, double r) { this.x = x; this.r = r; } /* * how long can the radius of the new balloon at position bx be * so that it touches this balloon */ public double calcR(long bx) { return (x - bx) * (x - bx) / (4 * r); } } }