Resumen de la prueba de búsqueda binaria del 17 de agosto
Enlace a la competición
Putnuación
| A. Cortar árboles | B. Comprar madera | C. Segmentación de array II | D. Comer helados | E. Saltando piedras | F. Vacas secando ropa |
|---|---|---|---|---|---|
| 100 | 80 | 100 | \(_{No resuelto:(}\) | 10 | 0 |
Puntuación total
\(_{Muy mal}\)
T1. P1873 [COCI 2011/2012 #5] EKO / Cortar árboles
Enlace al problema
Análisis del problema
Utilizar búsqueda binaria con una función de verificación
La función
verificarse usa para comprobar si la solución es válida
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 1000007;
int cantidadArboles, maderaRequerida;
vector<int> alturasArboles;
bool verificar(int alturaMinima)
{
int maderaObtenida = 0;
for (int i = 0; i < cantidadArboles; ++i)
{
if (alturasArboles[i] > alturaMinima)
{
maderaObtenida += (alturasArboles[i] - alturaMinima);
}
}
return maderaObtenida >= maderaRequerida;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> cantidadArboles >> maderaRequerida;
int maxAltura = 0;
alturasArboles.resize(cantidadArboles);
for (int i = 0; i < cantidadArboles; ++i)
{
cin >> alturasArboles[i];
maxAltura = max(maxAltura, alturasArboles[i]);
}
int izquierda = 1, derecha = maxAltura + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
izquierda = medio;
}
else
{
derecha = medio;
}
}
cout << izquierda << "\n";
return 0;
}
T2. B3880 [Información y Futuro 2015] Comprar madera
Enlace al problema
Código Incorrecto:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
vector<int> longitudes, cantidades;
int numProveedores, maderaRequerida;
bool verificar(int longitudMinima)
{
int totalMadera = 0;
for (int i = 0; i < numProveedores; ++i)
{
totalMadera += longitudes[i] / longitudMinima * cantidades[i];
if (totalMadera >= maderaRequerida)
{
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> numProveedores >> maderaRequerida >> longitudes[0] >> cantidades[0];
int maxLongitud = INT_MIN;
for (int i = 1; i < maderaRequerida; ++i)
{
longitudes[i] = ((longitudes[i-1] * 37011 + 10193) % 10000) + 1;
cantidades[i] = ((cantidades[i-1] * 73011 + 24793) % 100) + 1;
maxLongitud = max(longitudes[i], maxLongitud);
}
int izquierda = 0, derecha = maxLongitud + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
izquierda = medio;
}
else
{
derecha = medio;
}
}
cout << izquierda << "\n";
return 0;
}
/*
10 10000 8 20
*/
Análisis del problema
Mediante las dos fórmulas dadas en el problema:
- \(l_i=((l_{i-1}\times37011+10193) \bmod 10000)+1\)
- \(s_i=((s_{i-1}\times73011+24793) \bmod 100)+1\)
Y los valores iniciales proporcionados, calcular el tamaño de cada número subsiguiente
Utilizar búsqueda binaria con una función de verificación para encontrar la solución válida
Análisis del error
- Los detalles determinan el éxito
El problema dice:
Una línea con cuatro enteros \(n,m,l_1,s_1\). Donde \(l_1\) es la longitud de la madera del primer proveedor y \(s_1\) es la cantidad de madera del primer proveedor.
¡Y mi entrada por qué era \(m\) !!! \(_{Me enoja mucho}\)
Código Acpetado:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
vector<int> longitudes, cantidades;
int numProveedores, maderaRequerida;
bool verificar(int longitudMinima)
{
int totalMadera = 0;
for (int i = 0; i < numProveedores; ++i)
{
totalMadera += longitudes[i] / longitudMinima * cantidades[i];
if (totalMadera >= maderaRequerida)
{
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> numProveedores >> maderaRequerida >> longitudes[0] >> cantidades[0];
int maxLongitud = INT_MIN;
for (int i = 1; i < numProveedores; ++i)
{
longitudes[i] = ((longitudes[i-1] * 37011 + 10193) % 10000) + 1;
cantidades[i] = ((cantidades[i-1] * 73011 + 24793) % 100) + 1;
maxLongitud = max(longitudes[i], maxLongitud);
}
int izquierda = 0, derecha = maxLongitud + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
izquierda = medio;
}
else
{
derecha = medio;
}
}
cout << izquierda << "\n";
return 0;
}
/*
10 10000 8 20
*/
T3. P1182 Segmentación de array II
Enlace al problema
Problema previo P1181 Segmentación de array I
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
vector<int> elementos;
int n, m;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int suma = 0, segmentos = 1;
elementos.resize(n);
for (int i = 0; i < n; ++i)
{
cin >> elementos[i];
if (suma + elementos[i] <= m)
{
suma += elementos[i];
}
else
{
segmentos++;
suma = elementos[i];
}
}
cout << segmentos << "\n";
return 0;
}
Volviendo al problema actual (P1182)
Usar la mayor parte del código de P1181 como la función
verificarpara P1182
El código específico es el siguiente:
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
int n, m;
vector<int> elementos;
bool verificar(int maximoSegmento)
{
int contador = 1;
int sumaActual = 0;
for (int i = 0; i < n; ++i)
{
if (sumaActual + elementos[i] <= maximoSegmento)
{
sumaActual += elementos[i];
}
else
{
contador++;
sumaActual = elementos[i];
}
}
return contador <= m;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int sumaTotal = 0;
int maxElemento = 0;
elementos.resize(n);
for (int i = 0; i < n; ++i)
{
cin >> elementos[i];
maxElemento = max(maxElemento, elementos[i]);
sumaTotal += elementos[i];
}
int izquierda = maxElemento - 1;
int derecha = sumaTotal + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
derecha = medio;
}
else
{
izquierda = medio;
}
}
cout << derecha << "\n";
return 0;
}
/*
5 3
4 2 4 5 1
*/
T4. B3629 Comer helados
Enlace al problema
Código Incorrecto:
Análisis del problema
Al resolverlo, pensé en usar simulación + enumeración
El problema menciona búsqueda binaria
Pero no supe cómo aplicarla 😦
Cuantos más helados se compran, más palitos de helado quedan,
Más helados se canjearán y el total de helados aumentará
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
int nHelados;
bool verificar(int cantidadInicial)
{
int totalHelados = cantidadInicial;
int palitosRestantes = cantidadInicial;
while (palitosRestantes >= 3)
{
int nuevosHelados = palitosRestantes / 3;
palitosRestantes = palitosRestantes % 3;
totalHelados += nuevosHelados;
palitosRestantes += nuevosHelados;
}
return totalHelados >= nHelados;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> nHelados;
int izquierda = 1 - 1;
int derecha = nHelados + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
derecha = medio;
}
else
{
izquierda = medio;
}
}
cout << derecha << "\n";
return 0;
}
T5. P2678 [NOIP2015 Grupo avanzado] Saltando piedras
Enlace al problema
Código Incorrecto:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
vector<int> posicionesPiedras;
int longitudTotal, numPiedras, piedrasEliminar;
bool verificar(int distanciaMinima)
{
int saltos = 1;
int ultimaPosicion = 0;
for (int i = 1; i <= numPiedras; ++i)
{
if (posicionesPiedras[i] - posicionesPiedras[ultimaPosicion] <= distanciaMinima)
{
saltos++;
ultimaPosicion = i;
}
}
if (longitudTotal - posicionesPiedras[numPiedras] <= distanciaMinima)
{
saltos++;
}
if (posicionesPiedras[1] - 1 <= distanciaMinima)
{
saltos++;
}
return saltos <= piedrasEliminar;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> longitudTotal >> numPiedras >> piedrasEliminar;
posicionesPiedras.resize(numPiedras + 1);
for (int i = 1; i <= numPiedras; ++i)
{
cin >> posicionesPiedras[i];
}
int izquierda = 0;
int derecha = longitudTotal + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
izquierda = medio;
}
else
{
derecha = medio;
}
}
if (verificar(derecha))
{
cout << izquierda << "\n";
}
else
{
cout << derecha << "\n";
}
return 0;
}
\(_{Solo pasó el ejemplo y \#1}\) \(_{:(}\)
Análisis del problema
Se pueden eliminar como máximo \(m\) piedras, \(l\) representa la distancia mínima entre dos piedras Si la distancia entre dos piedras es menor que \(l\), significa que esa piedra debe ser eliminada La respuesta de la búsqueda binaria es \(l\), cuanto mayor es \(l\), menos piedras cumplen el requisito
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
const int MAXN = 100007;
int longitud, numPiedras, piedrasEliminar;
vector<int> posicionesPiedras;
bool verificar(int distanciaMinima)
{
int piedrasEliminadas = 0;
int posicionActual = 0;
for (int i = 1; i <= numPiedras; i++)
{
if (posicionesPiedras[i] - posicionesPiedras[posicionActual] < distanciaMinima)
{
piedrasEliminadas++;
}
else
{
posicionActual = i;
}
}
if (longitud - posicionesPiedras[posicionActual] < distanciaMinima)
{
piedrasEliminadas++;
}
return piedrasEliminadas <= piedrasEliminar;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> longitud >> numPiedras >> piedrasEliminar;
posicionesPiedras.resize(numPiedras + 1);
for (int i = 1; i <= numPiedras; ++i)
{
cin >> posicionesPiedras[i];
}
int izquierda = 0;
int derecha = longitud + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
izquierda = medio;
}
else
{
derecha = medio;
}
}
cout << izquierda << "\n";
return 0;
}
T6. P1843 Vacas secando ropa
\(_{El enunciado es interesante:)}\)
Análisis del problema
Usar búsqueda binaria con la función
verificar, dos amigos habitualesPero ¡
derechadebe ser lo suficientemente grande!!!Usé \(5000 \times 5000 + 1\)
Si se pueden secar todas las prendas en el tiempo
medio.Reducir el intervalo derecho
Nota: ¡Declarar
long long!
Código Aceptado:
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 500007;
vector<int> humedad;
int nPrendas, secadoNatural, secadoArtificial;
bool verificar(int tiempo)
{
int tiempoArtificial = 0;
for (int i = 0; i < nPrendas; i++)
{
int humedadRestante = humedad[i] - secadoNatural * tiempo;
if (humedadRestante > 0)
{
tiempoArtificial += ceil(humedadRestante * 1.0 / secadoArtificial);
}
}
return tiempoArtificial <= tiempo;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> nPrendas >> secadoNatural >> secadoArtificial;
humedad.resize(nPrendas);
for (int i = 0; i < nPrendas; ++i)
{
cin >> humedad[i];
}
int izquierda = 0;
int derecha = 5000 * 5000 + 1;
while (izquierda + 1 < derecha)
{
int medio = (izquierda + derecha) / 2;
if (verificar(medio))
{
derecha = medio;
}
else
{
izquierda = medio;
}
}
cout << derecha << "\n";
return 0;
}