Balloons
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 toca alguno de los globos inflados a su izquierda, y cómo comprobar esto de forma eficiente para todos los globos inflados anteriores. Como notación, es el radio y la coordenada x del globo .
Primero, determinemos cuándo dos globos se “tocan” calculando el radio máximo del segundo globo . Como la coordenada x del globo inflado anterior y su radio 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 . Con un poco de álgebra, podemos obtener una expresión para el radio máximo del segundo globo . Esto nos dice que el globo nunca puede tener un radio mayor que .
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 , que es demasiado lento. En su lugar, usamos la observación de que cualquier globo con e nunca será tocado por globos posteriores a . Por lo tanto, guardamos los globos inflados en una pila. Cada vez que queremos inflar un nuevo globo , comprobamos cuánto puede ser el radio de bajo la restricción del primer elemento de la pila. (Por supuesto, debe seguir siendo menor que el máximo dado .) Si , sacamos de la pila y comprobamos el siguiente elemento. no se volverá a comprobar. En caso contrario, si , podemos detener la comprobación y guardar nuestro globo recién inflado en esta pila.
Como quitamos el elemento de la pila una vez que queremos revisar más atrás, tenemos complejidad temporal .
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); }
}
}