Elegir un lenguaje
¿Qué lenguajes soporta USACO?
Los lenguajes más populares que soporta USACO son C++17 , Java y Python 3 . C también está soportado, pero es esencialmente una versión estrictamente inferior de C++ y no tiene las estructuras de datos incorporadas que se usan a menudo.
¿Cuáles son las diferencias entre C++11 y C++17?
Si recién se está empezando, probablemente no se usen características específicas de C++17, así que enviar en C++11 o en C++17 debería alcanzar. Para información sobre las características introducidas en C++11, C++14 y C++17, ver los enlaces de abajo.
¿Cuáles son las diferencias entre Python 2 y Python 3?
Como menciona el enlace de abajo, hay muchas diferencias entre Python 2 y 3. Python 3 es más nuevo y una mayoría abrumadora de competidores de USACO lo elige frente a Python 2.
¿Con qué lenguaje debería empezar?
En general, recomendamos lo siguiente:
- Si no se conoce ninguno de estos lenguajes, conviene empezar con C++, ya que quienes usan C++ no tienen que preocuparse tanto de que sus soluciones queden un factor constante por debajo del límite y no pasen (ver la sección de abajo para más detalles). Además, algunos módulos todavía no tienen soporte para Java ni Python.
- Si ya se conoce uno o más de estos lenguajes, se puede empezar con el que resulte más cómodo: siempre se puede cambiar a C++ más adelante.
¿Se puede pasar todos los problemas en todos los lenguajes?
C++ suele ser más rápido que Java, que a su vez suele ser más rápido que Python. Aunque tanto Python como Java reciben el doble del límite de tiempo de C++ en USACO, esto no ocurre en la mayoría de los otros sitios (p. ej. Codeforces, CSES). Incluso con los límites de tiempo extendidos, Python y Java a veces tienen problemas para pasar.
- El staff de USACO a veces se asegura de que sea posible obtener puntaje completo con C++, Python y Java en problemas de Bronce y Plata. Sin embargo, no está garantizado; por ejemplo, aquí hay un problema reciente de Bronce que no se esperaba que Python pasara.
- Python es demasiado lento para pasar la mayoría de los problemas de Oro y Platino.
- No tenemos ejemplos de problemas de USACO imposibles de pasar con Java, aunque hay casos en los que el código oficial en C++ no es lo suficientemente rápido para obtener puntaje completo si se traduce a código Java equivalente.
Ejemplo - Wormhole Sort (USACO Silver Jan 2020)
La solución en Java presentada en el análisis tarda más de 3s en ejecutarse (de un límite de tiempo de 4s).
import java.io.*;
import java.util.*;
public class wormsort {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("wormsort.in"));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int m = Integer.parseInt(st.nextToken());
loc = new int[n];
component = new int[n];
edges = new LinkedList[n];
for (int i = 0; i < n; i++) edges[i] = new LinkedList<>();
lhs = new int[m];
rhs = new int[m];
weight = new int[m];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) loc[i] = Integer.parseInt(st.nextToken()) - 1;
for (int i = 0; i < m; i++) {
st = new StringTokenizer(br.readLine());
lhs[i] = Integer.parseInt(st.nextToken()) - 1;
rhs[i] = Integer.parseInt(st.nextToken()) - 1;
weight[i] = Integer.parseInt(st.nextToken());
}
br.close();
int minW = 0;
int maxW = 1000000001;
while (minW != maxW) {
int mid = (minW + maxW + 1) / 2;
if (valid(mid)) minW = mid;
else maxW = mid - 1;
}
if (minW > 1e9) minW = -1;
PrintWriter pw =
new PrintWriter(new BufferedWriter(new FileWriter("wormsort.out")));
pw.println(minW);
pw.close();
}
static int[] loc, lhs, rhs, weight;
static LinkedList<Integer>[] edges;
static int[] component;
private static void dfs(int curr, int label) {
if (component[curr] == label) return;
component[curr] = label;
for (int child : edges[curr]) dfs(child, label);
}
private static boolean valid(int minW) {
Arrays.fill(component, -1);
for (int i = 0; i < edges.length; i++) edges[i].clear();
for (int i = 0; i < lhs.length; i++) {
if (weight[i] >= minW) {
edges[lhs[i]].add(rhs[i]);
edges[rhs[i]].add(lhs[i]);
}
}
int numcomps = 0;
for (int i = 0; i < component.length; i++) {
if (component[i] < 0) { dfs(i, numcomps++); }
}
for (int i = 0; i < loc.length; i++) {
if (component[i] != component[loc[i]]) return false;
}
return true;
}
}Una solución comparable en C++ corre en menos de 800ms:
#include <bits/stdc++.h>
using namespace std;
int n, m;
vector<int> loc, lhs, rhs, weight;
vector<vector<int>> edges;
vector<int> component;
void dfs(int curr, int label) {
if (component[curr] == label) return;
component[curr] = label;
for (int child : edges[curr]) dfs(child, label);
}
bool valid(int minW) {
component.assign(n, -1);
for (int i = 0; i < edges.size(); i++) edges[i].clear();
for (int i = 0; i < lhs.size(); i++) {
if (weight[i] >= minW) {
edges[lhs[i]].push_back(rhs[i]);
edges[rhs[i]].push_back(lhs[i]);
}
}
int numcomps = 0;
for (int i = 0; i < component.size(); i++) {
if (component[i] < 0) { dfs(i, numcomps++); }
}
for (int i = 0; i < loc.size(); i++) {
if (component[i] != component[loc[i]]) return false;
}
return true;
}
int main() {
freopen("wormsort.in", "r", stdin);
cin >> n >> m;
loc = vector<int>(n);
component = vector<int>(n);
edges = vector<vector<int>>(n);
lhs = vector<int>(m);
rhs = vector<int>(m);
weight = vector<int>(m);
for (int i = 0; i < n; i++) {
cin >> loc[i];
--loc[i];
}
for (int i = 0; i < m; i++) {
cin >> lhs[i] >> rhs[i] >> weight[i];
--lhs[i], --rhs[i];
}
int minW = 0;
int maxW = 1000000001;
while (minW != maxW) {
int mid = (minW + maxW + 1) / 2;
if (valid(mid)) minW = mid;
else maxW = mid - 1;
}
if (minW > 1e9) minW = -1;
freopen("wormsort.out", "w", stdout);
cout << minW << "\n";
}Una solución comparable en Python solo pasa los primeros cinco casos de prueba:
import sys
sys.setrecursionlimit(1000000)
sys.stdin = open("wormsort.in", "r")
sys.stdout = open("wormsort.out", "w")
n, m = map(int, input().split())
loc = [0] * n
component = [0] * n
edges = [[] for i in range(n)]
lhs = [0] * m
rhs = [0] * m
weight = [0] * m
def dfs(curr, label):
if component[curr] == label:
return
component[curr] = label
for child in edges[curr]:
dfs(child, label)
def valid(minW):
global component
component = [-1] * n
for i in range(n):
edges[i].clear()
for i in range(m):
if weight[i] >= minW:
edges[lhs[i]].append(rhs[i])
edges[rhs[i]].append(lhs[i])
numcomps = 0
for i in range(n):
if component[i] < 0:
dfs(i, numcomps)
numcomps += 1
for i in range(n):
if component[i] != component[loc[i]]:
return False
return True
loc = list(map(lambda x: int(x) - 1, input().split()))
for i in range(m):
lhs[i], rhs[i], weight[i] = map(int, input().split())
lhs[i] -= 1
rhs[i] -= 1
minW = 0
maxW = 1000000001
while minW != maxW:
mid = (minW + maxW + 1) // 2
if valid(mid):
minW = mid
else:
maxW = mid - 1
if minW > 1e9:
minW = -1
print(minW)Es posible optimizar este enfoque para pasar todos los casos de prueba. Tarda alrededor de 3.8s en ejecutarse.
def main():
f = open("wormsort.in", "rb")
n, m = map(int, f.readline().split())
loc = [*map(int, f.readline().split())]
edges = [[] for _ in range(n)]
weights = []
def valid(loc, minW):
component = [-1] * n
numcomps = 0
for i in range(n):
if component[i] != component[loc[i] - 1]:
return False
elif component[i] == -1:
todo = [i]
component[i] = numcomps
for node in todo:
for child, weight in edges[node]:
if component[child] == -1 and weight >= minW:
component[child] = numcomps
todo.append(child)
numcomps += 1
return True
for line in f:
a, b, w = map(int, line.split())
edges[a - 1].append((b - 1, w))
edges[b - 1].append((a - 1, w))
weights.append(w)
weights.sort()
weights.append(10**9 + 1)
lo, hi = 0, m + 1
while lo != hi:
mid = (lo + hi) // 2
if valid(loc, weights[mid]):
lo = mid + 1
else:
hi = mid
open("wormsort.out", "w").write(f"{-1 if lo == m + 1 else weights[lo-1]}\n")
main()Por último, el enfoque de abajo usa DSU (un tema de Oro), y tarda alrededor de 1s en ejecutarse:
# Author: Nicolas Hsu
file = open("wormsort.in")
N, M = map(int, file.readline().split())
P = tuple(map(int, ("0 " + file.readline()).split()))
W = [tuple(map(int, file.readline().split())) for i in range(M)]
W.sort(key=lambda w: -w[2])
par = list(range(N + 1))
def find(u):
if par[u] == u:
return u
else:
par[u] = find(par[u])
return par[u]
w = -1
for n in range(1, N + 1):
while find(n) != find(P[n]):
w += 1
par[find(W[w][1])] = find(W[w][0])
out = open("wormsort.out", "w")
out.write("-1" if w == -1 else str(W[w][2]))
out.close()¿Qué se espera que sepa?
Hay que saber programar en al menos uno de los lenguajes listados arriba antes de continuar con la sección de Bronce de esta guía. Para una lista más detallada de lo que se debería saber, leer el módulo “Conocimientos esperados”.