Final Nacional Trinidad 2011 - Solucionario

Anuncio
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()));
}
}
Descargar