¡Hola chicos! Muchas gracias por participar. Esta es la primera ocasión en la que el Club de Programación Competitiva (CPCFI) escribe problemas originales para un concurso, y nos hizo muchísima ilusión que los resolvieran.
Para quienes tengan la curiosidad, todos los protagonistas de los problemas son personas que pertenecen al CPCFI. Somos una comunidad muy unida y nos hace mucha gracia verlos como protagonistas los problemas. Esperamos que en algún momento de sus carreras consideren unirse al club, que siempre tendrá las puertas abiertas para gente que busque desafíos complicados y una comunidad unida que los apoyará incondicionalmente.
Les deseamos lo mejor en su formación personal y profesional y esperamos verlos de nuevo en la fase final.
Agradecimientos especiales a RacsoFractal, quién hizo posible la creación de estos problemas para el concurso y me invitó a colaborar en este desafío tan grande para el CPCFI.
También queremos agradecer a todos los testers de los problemas, que nos ayudaron a afinar detalles y a corregir errores: ELeon, AlexJzG, lamocha, Nitter, salazarislas.daniel, Warddd,AldoEZ_21, zum, eve181836
Itera la cadena solo una vez.
Itera la cadena y con un condicional revisa si el caracter actual es 'G' o 'g', si se cumple, no imprimas ese caracter.
Si usas Python o Java puedes usar el método .replace() y sustituir las 'G' y 'g' con el caracter vacío ''
#include<stdio.h>
#include<string.h>
#define or ||
void solve(){
int n; scanf("%d",&n);
char str[n+1];
scanf("%s",str);
for(int i=0; i<n; i++){
if(str[i] == 'G' or str[i] == 'g'){
continue;
}
printf("%c",str[i]);
}
printf("\n");
}
int main(){
solve();
return 0;
}
n = int(input())
s = input()
print(s.replace('G','').replace('g',''))
671145B. Entrenamiento de equipo II
671145C. Lanzadardos inexperto
$$$r = \sqrt{(x-u)^2+(y-v)^2}$$$
Donde $$$x$$$ e $$$y$$$ son el centro de cualquier círculo y $$$u$$$ y $$$v$$$ son cualquier punto al que Zum tira un dardo.
Sea $$$r_{act}$$$ el radio del punto actual al centro de cualquier círculo y $$$r$$$ el radio de un círculo. Si $$$r_{act} \lt = r$$$, entonces el punto actual está dentro del círculo de radio $$$r$$$.
Para cada dardo que tira Zum, debemos calcular su distancia con respecto al centro de ambos círculos mediante la fórmula de la distancia euclidiana, nos evitaremos sacar la raíz cuadrada manejando el cuadrado de todos los términos. La distancia al centro del círculo grande es: $$$D_i^2 = (u_i - x_1)^2 + (v_i - y_1)^2$$$. Y la distancia al centro del círculo pequeño es $$$d_i^2 = (u_i - x_2)^2 + (v_i - y_2)^2$$$. Si $$$d_i^2$$$ es menor o igual que el radio del circulo pequeño al cuadrado, llamémosle $$$r_1^2$$$ ($$$d_i^2 \leq r_1^2$$$), se imprime "YAAAAY!". Si esta condición no se cumple, revisamos la distancia al centro del círculo grande ($$$D_i^2 \leq r_1^2$$$), si se cumple, imprimimos "MEH", en caso contrario, terminamos imprimiendo "BUUUUU!".
#include<stdio.h>
double distance(double x, double y, double h, double k) {
return (x - h) * (x - h) + (y - k) * (y - k);
}
void solve(){
double r1,x1,y1; scanf("%lf %lf %lf",&r1, &x1, &y1);
double r2,x2,y2; scanf("%lf %lf %lf",&r2, &x2, &y2);
int q; scanf("%d", &q);
for(int i=0; i<q; i++){
double u,v; scanf("%lf %lf", &u,&v);
if(distance(u, v, x2, y2)<= r2*r2){
printf("YAAAAY!\n");
continue;
}
if(distance(u, v, x1, y1) <= r1*r1){
printf("MEH\n");
continue;
}
printf("BUUUUU!\n");
}
}
int main(){
solve();
return 0;
}
671145D. El billar no es de vagos II
Calcula la distancia de cada número a su primo más cercano simulando las dos operaciones.
Ordena esas distancias.
Primero debemos generar un arreglo del mismo tamaño que el arreglo original, es decir, tamaño $$$N$$$, llamemos a este arreglo dist[N]. Para cada elemento del arreglo original $$$a_i$$$, guardaremos en $$$dist_i$$$ la distancia a su primo más cercano. Vamos a dividir el número entre dos hasta llegar a cero, por cada división, vamos a revisar qué tan lejos está el número actual de un primo tanto hacia arriba como hacia abajo, mientras llevamos conteo del valor mínimo actual, es decir, si la división actual + su distancia al primo más cercano es menor que el valor que tenemos actualmente, lo actualizamos.
Una vez que tengamos todas las distancias calculadas vamos a ordenarlas con cualquier algoritmo de ordenamiento (que no sea Bogo Sort ;D) y nuestra respuesta será ir iterando en orden este nuevo arreglo, restándole la distancia actual a nuestra $$$K$$$, que es las operaciones que tenemos disponibles.
#include<stdio.h>
#include<stdbool.h>
#define and &&
#define MAX_VAL 1050
#define ll long long
#define INF 200000000
int min(int a, int b){
return a < b ? a : b;
}
void bubbleSort(int n, int *arr){
for(int i=0; i<n-1; i++){
for(int j=0; j<n-i-1; j++){
if(arr[j] > arr[j+1]){
int tmp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = tmp;
}
}
}
}
bool isPrime(ll n){
if(n==1) return false;
if(n==2) return true;
if(n%2 == 0) return false;
for(int i=3; i<n; i+=2){
if(n%i == 0) return false;
}
return true;
}
int distToPrime(int n){
if (isPrime(n)) return 0;
int dist = 1;
while(true){
if (n - dist >= 2 && isPrime(n - dist)) return dist;
if (isPrime(n + dist)) return dist;
dist++;
}
}
int distance(int n){
int min_cost = INF;
int divisions = 0;
while (n > 0) {
int cost = divisions + distToPrime(n);
min_cost = min(min_cost, cost);
n /= 2;
divisions++;
}
int zero = divisions + 2;
min_cost = min(min_cost, zero);
return min_cost;
}
void solve(){
int n, k;
scanf("%d %d", &n, &k);
int board[n], costs[n];
for(int i=0; i<n; i++){
scanf("%d", &board[i]);
costs[i] = distance(board[i]);
}
bubbleSort(n, costs);
int numPrimes = 0;
for(int i=0; i<n; i++){
if(costs[i] <= k){
numPrimes++;
k -= costs[i];
}else{
break;
}
}
printf("%d\n", numPrimes);
}
int main(){
solve();
return 0;
}
En programación competitiva no es usual que una solución así funcione, debido a que estamos probando por fuerza bruta muchas posibles distancias, así como checar uno por uno los números primos y como cereza en el pastel, estamos usando un ordenamiento burbuja, que no es un algoritmo eficiente para ordenar. Hay muchos temas involucrados para lograr una solución eficiente para este problema. Sin embargo, describiremos la solución que nosotros esperábamos para este problema y dejamos como ejercicio para el lector la lectura sobre estos temas.
En el caso de que los límites del problema fueran $$$1 \leq N,M,a_i, \leq 10^5$$$, la solución necesaria sería en cuanto a idea la misma, pero usaremos métodos distintos para lograrlo.
Primero, necesitamos precomputar todos los primos hasta el elemento más grande del arreglo. Para esto se utiliza un algoritmo llamado Criba de Eratóstenes, que nos devolverá una tabla que nos dirá si el i-ésimo número de la tabla es primo. Con el fin de consultar de forma rápida si cualquier número es primo mediante consultar la tabla.
Con esto podremos probar las distancias a los primos de forma rápida. Para ordenar, hay múltiples algoritmos eficientes que nos permiten ordenar. En la solución del ejemplo se usa el ordenamiento por conteo (Counting Sort).
Shoutout a AlexJzG por la solución.
#include <stdio.h>
#define MAX 2002
int sieve[MAX], nums[MAX], min_dist[MAX], sorted_dist[MAX];
void get_primes() {
sieve[0] = sieve[1] = 1;
for (int i = 2; i < MAX; i++) {
if (sieve[i]) {
continue;
}
for (int j = i * 2; j < MAX; j += i) {
sieve[j] = 1;
}
}
}
void get_min_dist() {
int last_prime = MAX + 100;
for (int i = MAX - 1; i >= 0; i--) {
if (sieve[i] == 0) {
last_prime = i;
}
if (min_dist[i] == 0) {
min_dist[i] = last_prime - i;
} else if (last_prime - i < min_dist[i]) {
min_dist[i] = last_prime - i;
}
}
last_prime = -100;
for (int i = 0; i < MAX; i++) {
if (sieve[i] == 0) {
last_prime = i;
}
if (min_dist[i] == 0) {
min_dist[i] = i - last_prime;
} else if (i - last_prime < min_dist[i]) {
min_dist[i] = i - last_prime;
}
if(min_dist[i/2] + 1 < min_dist[i]){
min_dist[i] = min_dist[i/2] + 1;
}
}
}
void init() {
// Get primes (sieve[i] = 0 is prime)
get_primes();
// Get min distance to p rimes
get_min_dist();
}
void counting_sort() {
for (int i = 0; i < MAX; i++) {
sorted_dist[min_dist[i]] += nums[i];
}
}
int max_primes(int m) {
int ans = 0;
for (int i = 0; i < MAX; i++) {
while (m >= i && sorted_dist[i] > 0) {
ans++;
m -= i;
sorted_dist[i]--;
}
}
return ans;
}
int main() {
init();
int n, m, a;
scanf("%d %d\n", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%d", &a);
nums[a]++;
}
counting_sort();
printf("%d\n", max_primes(m));
}
Usa tres ciclos for anidados.
Para cada combinación, checa si las raíces de esa combinación de coeficientes es igual a las raíces que te da David
Usa un triple for para probar todas las combinaciones de coeficientes $$$a,b,c$$$, obtén las raíces de cada ecuación que formen los coeficientes con la fórmula de Bhaskara (AKA "La chicharronera"): $$$\frac{-b\pm \sqrt{b^2 - 4ac}}{2a}$$$. Esto siempre y cuando compruebes que la ecuación no genera números complejos, esto mediante evaluar la desigualdad del discriminante $$$b^2 \gt = 4ac$$$
#include<stdio.h>
#include<stdbool.h>
#include<math.h>
#define EPS 1e-6
typedef struct{
float x1,x2;
}Roots;
bool isComplex(int a, int b, int c){
return b*b - 4*a*c < 0;
}
Roots bhaskara(int a, int b, int c){
Roots answer;
float discriminant = b*b - 4*a*c;
answer.x1 = (-b+sqrt(discriminant))/(2*a);
answer.x2 = (-b-sqrt(discriminant))/(2*a);
return answer;
}
void solve(){
int n,x1,x2; scanf("%d %d %d",&n, &x1, &x2);
int as[n], bs[n], cs[n];
for(int i=0; i<n; i++){
scanf("%d %d %d", &as[i],&bs[i],&cs[i]);
}
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
for(int k=0; k<n; k++){
if(!isComplex(as[i],bs[j],cs[k])){
Roots tmp = bhaskara(as[i], bs[j], cs[k]);
bool match_direct = (fabs(tmp.x1 - x1) < EPS && fabs(tmp.x2 - x2) < EPS);
bool match_swapped = (fabs(tmp.x1 - x2) < EPS && fabs(tmp.x2 - x1) < EPS);
if (match_direct || match_swapped) {
printf("%d %d %d\n", as[i], bs[j], cs[k]);
return;
}
}
}
}
}
}
int main(){
solve();
return 0;
}
import math
EPS = 1e-9
def isComplex(a: int, b: int, c: int) -> bool:
return b*b — 4*a*c < 0
def bhaskara(a: int, b: int, c:int):
return (-b+math.sqrt(b*b — 4*a*c))/(2*a), (-b-math.sqrt(b*b — 4*a*c))/(2*a)
n,x1,x2 = [int(x) for x in input().split()]
a_s = []
b_s = []
c_s = []
for _ in range(n):
a,b,c = [int(x) for x in input().split()]
a_s.append(a)
b_s.append(b)
c_s.append(c)
for i in range(n):
for j in range(n):
for k in range(n):
if(not isComplex(a_s[i],b_s[j],c_s[k])):
tx1, tx2 = bhaskara(a_s[i],b_s[j],c_s[k])
match_direct = abs(tx1 — x1) < EPS and abs(tx2 — x2) < EPS
match_swapped = abs(tx1 — x2) < EPS and abs(tx2 — x1) < EPS
if match_direct or match_swapped:
print(f'{a_s[i]} {b_s[j]} {c_s[k]}')
exit()
Las formulas de Vieta nos permiten establecer una relación entre raíces y coeficientes. En concreto, para una ecuación de segundo grado tenemos las siguientes fórmulas.
Suma de las raíces
Producto de las raíces
Con esto, tenemos dos ecuaciones que dependen de $$$a$$$, por lo tanto, ahora solo necesitamos comprobar para cada $$$a$$$ si existe una $$$b$$$ y una $$$c$$$ que cumplan las dos ecuaciones.
Para hacer esto de forma eficiente podemos guardar todas las $$$b$$$ y $$$c$$$ en dos sets y buscar los valores en sustituyendo los valores de las raíces y de cada $$$a$$$ en ambas ecuaciones.
def sumOfRoots(a: int, x1: int, x2:int) -> int:
return -a*(x1+x2)
def productOfRoots(a: int, x1:int, x2:int) -> int:
return a*(x1*x2)
n,x1,x2 = [int(x) for x in input().split()]
a_s = []
b_s = set()
c_s = set()
for _ in range(n):
a,b,c = [int(x) for x in input().split()]
a_s.append(a)
b_s.add(b)
c_s.add(c)
for a in a_s:
b = sumOfRoots(a,x1,x2)
c = productOfRoots(a,x1,x2)
if b in b_s and c in c_s:
print(f'{a} {b} {c}')
exit()



