Olimpiada Boliviana de Informática Estado Plurinacional de Bolivia, 19 de septiembre de 2011 Examen de Nivel 2..............................................................................................................2 Problema A: Múltiplo Pequeño .......................................................................................2 Problema B: El resto ........................................................................................................3 Problema C: Cuando Ver Películas..................................................................................4 Problema D: La granja de Juan y José .............................................................................5 Examen de Nivel 3..............................................................................................................6 Problema A: Siempre Solo...............................................................................................6 Problema B: La nueva pieza de ajedrez ...........................................................................8 Problema C: Cuando Ver Películas..................................................................................9 Problema D: Soluciones.................................................................................................10 Examen de Nivel 2 Problema A: Múltiplo Pequeño Muchos números naturales de base 10 consisten en múltiples números 1 y 0. Por ejemplo el número once 11, el diez 10 el ciento uno 101. Dado un numero X se desea conocer cual es el múltiplo más pequeño de X que puede formarse exclusivamente de unos y ceros. Si X = 55 el múltiplo más pequeño que podemos formar con unos y ceros es 110. Entrada En la entrada defina X = 7. Salida Escriba en una línea el número formado por unos y ceros más pequeño que es múltiplo de X. Ejemplos X 2 5 10 25 Respuesta 10 10 10 100 Solución /* Problema : Multiplo Pequeño * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> using namespace std; bool verificar( int m ) { while(m>0) { if( m %10 > 1 ) return false; m = m/10; } return true; } int main() { // Variable de trabajo int x = 7; // Variables auxiliares int m = 0; while( true ) { m++; if( verificar( x*m ) ) { cout << (x*m) << endl; break; //salir del while } } return 0; } Problema B: El resto Los números de Fibonacci se genera con la ecuación: f n = f n−1 + f n−2 La lista de números generados por esta secuencia son 1, 1, 2, 3, 5, 8, 13, 21,... etc. Los primeros números de esta secuencia se definen como sigue: i Fib(i) 0 1 1 1 2 2 3 3 4 5 5 8 6 13 7 21 Dado un número X se desea conocer el resto de dividir un determinado número Fibonacci por X. Por ejemplo si X = 7, y i = 6 en resto seria 13 %7 = 6. Entrada Defina en su programa i = 19 y X = 29. Salida Escriba en una línea el resto de dividir el Fibonacci i por X. Ejemplos N 3 6 3 i 7 9 11 Respuesta 3 4 3 Solución /* Problema : El Resto * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> using namespace std; int main() { // Variables de trabajo int i = 19, x = 29; // Variables auxiliares int f[20], n; f[0]=1; f[1]=1; for( n = 2; n<=19; n++ ) { f[n] = f[n-1] + f[n-2]; } cout << (f[i]%x) << endl; return 0; } Problema C: Cuando Ver Películas En la ciudad de La Paz existen diferentes lugares para ver películas pero ninguno como el Cine IOI. El precio de las entradas en este cine varía dependiendo el día, 10 Bolivianos los días Miércoles 30 Bolivianos los Sábados y Domingos y 20 Bolivianos los demás días. Considerando que hoy es Lunes y solo podemos ver una película al día, ayúdanos a elegir los días en los que tenemos que ver N películas de tal forma que nos salga lo mas económico posible. Entrada Defina en su programa los días para ver películas en 92 y el número de películas a ver en 62. Entrada Por cada caso de prueba imprima una línea con el mínimo costo para ver películas. Ejemplos Días para ver Películas 2 3 7 Número Películas 1 1 7 Solución /* Problema : Cuando ver Peliculas * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> #include<vector> #include<algorithm> using namespace std; int precios[] ={20,20,10,20,20,30,30}; int resolver( int d, int p ) { int resp = 0, i; vector<int> dias; for( i=0; i<d; i++ ) dias.push_back( precios[i%7] ); sort( dias.begin(), dias.end() ); for( i=0; i<p; i++ ) resp = resp + dias[i]; return resp; } int main(){ int dia = 92, peliculas = 62; int resultado = resolver( dia, peliculas ); cout << resultado << endl; return 0; } Resultado 20 10 150 Problema D: La granja de Juan y José Juan y José tienen una granja de gallinas y vacas, un día se les ocurrió contar el número de cabezas y el número de patas de los animales (vacas y gallinas) en la granja. Juan contó un total de 3 cabezas y José contó un total de 8 patas del total de animales en la granja. Juan hizo algunos cálculos y determino que existen 3 gallinas y 1 vaca. José noto que Juan tarda demasiado en hacer los cálculos, así que pide tu ayuda para poder obtener una solución general del problema. Nota.Una gallina tiene 1 cabeza y 2 patas. Una vaca tiene 1 cabeza y 4 patas. Si la solución existe, esta siempre es única. Entrada En su programa defina el numero de cabezas = 8200 y del patas = 18844. Salida Escriba en la salida separados por un espacio el número de gallinas y el segundo es el número de vacas. En caso de no existir solución imprimir -1; Ejemplos Cabezas 3 10 1 Patas 8 40 3 Resultado 2 1 0 10 -1 Solución /* Problema : La Granja de Juan y Jose * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> using namespace std; void resolver( int cabezas, int patas ) { if(patas%2!=0) { printf("-1\n"); return; } int vacas = patas/2-cabezas; int gallinas = cabezas-vacas; if(vacas<0 || gallinas<0){ printf("-1\n"); return; } cout<< gallinas << " " << vacas << endl; } int main(){ int cabezas=8200, patas=18844; resolver( cabezas, patas ); return 0; } Examen de Nivel 3 Problema A: Siempre Solo En el país de Code-livia desde hace mucho tiempo existía una mente inimaginablemente brillante, tanto que decidió solo juntarse con los suyos pero poco a poco se fue quedando solo, su nombre es Moss. Ahora necesitamos formar un equipo para la competencia de programación más prestigiosa, la ACM ICPC y necesitamos encontrarlo. Sabemos que él esta solo y es diferente a los demás. Se logro clasificar con letras a varias mentes brillantes de acuerdo a su nivel pero nosotros necesitamos únicamente a Moss. Entrada Por cada caso de prueba se ingresaran dos líneas. En la primera hay un número entero N (3 ≤ N ≤ 1000) el número de personas clasificadas. La segunda línea contiene una cadena de caracteres de longitud N, con letras minúsculas y mayúsculas (de la a hasta la z y desde la A hasta la Z). La entrada terminara con N igual a 0 (cero). Salida Por cada caso de prueba devolver la posición en la que se encuentra Moss comenzando de 1. Se garantiza que hay solo una letra que no se repite. Ejemplos de entrada 4 AaAA 5 bbxaa 6 XBBbBX 0 Ejemplos de salida 2 3 4 Solución /* Problema : Siempre Solo * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> using namespace std; int resolver( string cadena, int n ) { int i,j; bool igual; for( i=0; i<n; i++ ) { igual = false; for(j = 0; j<n; j++ ) { if(cadena[i]==cadena[j] && i!=j) { igual = true; } } if( igual == false ) { return i+1; } } return 0;//ERROR } int main(){ int n; string cadena; while( true ) { cin >> n; if( n==0 ) break; cin >> cadena; cout << resolver( cadena, n ) << endl; } return 0; } Problema B: La nueva pieza de ajedrez El ajedrez se juega en un tablero de 8x8 con diferentes tipos de fichas, que se mueven de diferente forma. Se está evaluando adicionar un nuevo tipo de ficha al tablero y uno de los aspectos que queremos analizar, es su alcance en el tablero. El movimiento de una ficha, se puede determinar por movimientos horizontales y verticales. Por ejemplo, el caballo se puede mover una casilla horizontalmente y dos verticales o dos horizontales y una vertical. En el diagrama se puede observar como un caballo (la casilla C), en un movimiento, puede moverse a 8 posiciones (las marcadas con *). * * * * C * * * * Dados los tipos de movimientos de la nueva ficha, determinar a cuantas casillas puede llegar después de varios movimientos en un tablero de NxN si la ficha comenzará en una de las esquinas del tablero. Entrada • Q = Número de casos de prueba Por cada caso de prueba: • • N = Tamaño del tablero cuadrado NT = Número de tipos de movimiento Por cada tipo de movimiento • X Y, donde X es el movimiento horizontal (izquierda o derecha), e Y es movimiento vertical (arriba o abajo) Salida Por cada caso de prueba, el número de casillas que la nueva pieza de ajedrez puede alcanzar en varias movidas. Ejemplos de entrada 1 3 8 1 2 1 -2 2 1 2 -1 -2 1 -2 -1 -1 2 -1 -2 Ejemplos de salida 8 El caso de ejemplo es el del caballo, tenemos ocho tipos de movimientos indicados en la entrada: X 1 1 2 2 -1 -1 -2 -2 Y 2 -2 1 -1 2 -2 1 -1 Partiendo de una esquina puede llegar a 8 lugares en múltiples movimientos. /** * @author Gareve * @problem La nueva ficha de ajedrez */ #define DEBUG #ifndef NDEBUG #define DBG(a) cout<<__LINE__<<": "<<#a<<"= "<<a<<endl; #else #define DBG(a) ; #endif #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <algorithm> #include <cstring> #include <cassert> #include <queue> #include <set> #include <map> #include <cmath> #define foreach(IT,C) for(typeof(C.begin())IT=C.begin();IT!=C.end();IT++) using namespace std; const int MAX = 109; bool m[MAX][MAX]; void resuelva(){ int n,x,y,xx,yy,nm; int res = 0; queue<int> qx,qy; scanf("%d",&n); scanf("%d",&nm); int mx[nm],my[nm]; for(int i=0;i<nm;i++){ scanf("%d %d",&mx[i],&my[i]); } memset(m,false,sizeof(m)); m[1][1]=true; res ++; qx.push(1); qy.push(1); while(!qx.empty()){ x = qx.front();qx.pop(); y = qy.front();qy.pop(); for(int i=0;i<nm;i++){ xx = x + mx[i]; yy = y + my[i]; if(yy>=1 and xx>=1 and yy<=n and xx<=n and m[yy][xx] == false){ qx.push(xx); qy.push(yy); m[yy][xx]=true; res++; } } } printf("%d\n",res); } int main(){ int q; scanf("%d",&q); for(int i=1;i<=q;i++) resuelva(); } Problema C: Cuando Ver Películas En la ciudad de La Paz existen diferentes lugares para ver películas pero ninguno como el Cine-IOI. El precio de las entradas en este cine varía dependiendo el día, 10 Bolivianos los días Miércoles 30 Bolivianos los Sábados y Domingos y 20 Bolivianos los demás días. Considerando que hoy es Lunes y solo podemos ver una película al día, ayúdanos a elegir los días en los que tenemos que ver N películas de tal forma que nos salga lo mas económico posible. Entrada En la primera línea de entrada nos darán un número T que representa la cantidad de casos de prueba. Por cada caso de prueba hay una línea que contiene dos números C (1 ≤ C ≤ 100) y N (1 ≤ N ≤ C). Donde C es el número de días que hay para ver N películas. Salida Por cada caso de prueba imprima una línea con el mínimo costo para ver N películas en C días. Ejemplos de entrada 5 2 1 3 1 7 7 14 7 92 62 Ejemplos de salida 20 10 150 120 1110 Solución /* Problema : Cuando ver Peliculas * Lenguaje : C++ * Autor : Alberto Suxo ******************************/ #include<iostream> #include<vector> #include<algorithm> using namespace std; int precios[] ={20,20,10,20,20,30,30}; int resolver( int d, int p ) { int resp = 0, i; vector<int> dias; for( i=0; i<d; i++ ) dias.push_back( precios[i%7] ); sort( dias.begin(), dias.end() ); for( i=0; i<p; i++ ) resp = resp + dias[i]; return resp; } int main(){ int t; int dia, peliculas; cin >> t; while( t-- ) { cin >> dia >> peliculas; int resultado = resolver( dia, peliculas ); cout << resultado << endl; } return 0; } Problema D: Soluciones Un laboratorio científico afiliado a la IOI Bolivia tiene diferentes tipos de soluciones ácidas y alcalinas. Cada solución tiene asignado un entero que representa su característica. Los enteros positivos de 1 a 1,000,000,000, representan soluciones ácidas mientras que los enteros negativos de -1 a -1,000,000,000, representan las soluciones alcalinas. Los valores característicos para la mezcla del mismo monto de las 2 soluciones esta definido como la suma de los valores característicos de las dos soluciones mezcladas. Este laboratorio quiere hacer una mezcla con los valores característicos más cercanos al cero cuando el mismo monto de las dos soluciones han sido mezcladas. Por ejemplo, una lista de valores característicos es dada [-99, -2, -1, 4, 98]. En este caso, la suma de los enteros -99 y 98 da -1, que es el valor más cercano a 0. Note que es posible de hacer una mezcla con un valor cercano a 0 mezclando dos soluciones alcalinas o dos soluciones ácidas. Una lista de valores característicos para valores ácidos y alcalinos es dado. Escriba un programa que imprima el valor característico más cercano a 0 cuando estos son mezclados juntos. Entrada • El número T de casos de prueba. Cada caso de prueba consiste: • • El número total de soluciones, (2 ≤ N ≤ 100; 000), es dado en la primera línea. En la segunda línea, N números de valores característicos es dado en orden ascendente. Estos números son mayores que o iguales a -1,000,000 y menores o iguales a 1,000,000. Estos valores característicos son únicos. Salida Imprima el valor más cercano a 0 que puede ser formado al mezclar dos soluciones. Si existieran varios valores igual de cercanos al cero, imprima el menor. Ejemplos de entrada 3 5 -99 -2 -1 4 98 4 -100 -2 -1 103 4 -8 -4 4 8 Ejemplos de salida -1 -3 0 En los casos de ejemplo, -1 se puede conseguir mezclando -99 con 98; y -3 se puede conseguir mezclando -2 y -1, en ambos ejemplos no se puede conseguir un valor característico más cercano al cero. Y en el último ejemplo, se pueden conseguir 4 y -4 en el que ambos son igual de cercanos al 0, por lo tanto, se usa el menor. /** * @author Gareve * @problem Soluciones */ #define DEBUG #ifndef NDEBUG #define DBG(a) cout<<__LINE__<<": "<<#a<<"= "<<a<<endl; #else #define DBG(a) ; #endif #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <vector> #include <algorithm> #include <cstring> #include <cassert> #include <queue> #include <set> #include <map> #include <cmath> #define foreach(IT,C) for(typeof(C.begin())IT=C.begin();IT!=C.end();IT++) using namespace std; const int MAX = 100009; int vc[MAX],n; int menor(int a,int b){ if(abs(a) == abs(b)) return min(a,b); if(abs(a) < abs(b)) return a; else return b; } int cercano_a_cero(int pos){ int v = -vc[pos];//idealmente, -v hace que sea cero int a = 0,b = n-1,mit; while(a<b){//Búsqueda binaria mit = (a+b)/2; if(vc[mit] > v) b = mit; else a = mit+1; } //b apunta a un valor <= a donde debería hacerse cero int r = 9000001; for(int k=-1;k<=1;k++)//revisamos valores cercanos al punto optimo if(b + k >= 0 and b + k < n and b + k != pos) r = menor(r,vc[b+k] + vc[pos]); return r; } int resuelva(){ int r = 9000001; for(int i=0;i<n;i++){ r = menor(r,cercano_a_cero(i)); //printf("## %d %d [%d]\n",vc[i],cercano_a_cero(i),r); } return r; } int brute_force(int pos){ int r = 9000000; for(int i=0;i<n;i++){ if(i != pos) r = menor(r,vc[pos] + vc[i]); } //printf(">> %d = %d\n",vc[pos],r); return r; } int resolve_brute_force(){ int r = 9000001; for(int i=0;i<n;i++) r = menor(r,brute_force(i)); return r; } void lectura(){ scanf("%d",&n); for(int i=0;i<n;i++) scanf("%d",&vc[i]); sort(vc,vc+n); //entrada ordenada } int main(){ int q; scanf("%d",&q); for(int i=1;i<=q;i++){ lectura(); printf("%d\n",resuelva()); //assert(n>1000 or (resuelva() == resolve_brute_force())); } }