Тесты жюри и некоторые решения

advertisement
Олимпиада 2009
Задача №1. (4 балла)
В массиве a[1]...a[n] встречаются по одному разу все целые числа от 0 до n, кроме одного.
Найти пропущенное число
Формат входных данных:
Первая строка входных данных состоит из одного числа n, количества элементов массива;
в последующих строках – элементы массива.
Формат выходных данных:
пропущенное число
Тест 1 (2 балла)
input.txt:
1
0
output.txt:
1
Тест 1 (2 балла)
input.txt:
10
1234567890
output.txt:
10
Решение
Логика задачи проста: числа помещаются в массив. При просмотре 1 массива, элементы
другого массива той же длины приравниваются к 1 (true), если в 1-м массиве есть число,
равное индексу элемента 2-го массива. Элемент 2-го массива, с индексом-числом,
которого нет в 1-м массиве, остается равным 0(false) – значению, которое заносится
компилятором.
Например, так (решение победителя Филиппова Д.):
const lim = 32000;
var a: array[0..lim] of integer;
b: array[0..lim] of boolean;
i, n: longint;
begin
readln(n);
for i:= 1 to n do begin
readln(a[i]);
b[a[i]]:= true;
end;
for i:= 0 to n do
if b[i] = false then begin
write(i);
break;
end;
end.
Задача №2.(5 баллов)
Определите, какая из цифр в десятичной записи введенного числа встречается чаще всего.
Выведите на экран эту цифру и число раз, которое она встречается. Если таких цифр
несколько, выведите их все.
1
Тест 1 (2 балла)
input.txt:
1434
output.txt:
4 2(раза)
Тест 3 (3 балла)
input.txt:
11344
output.txt:
1 4 2(раза)
Решение:
Приемы решения таких задач можно увидеть в задаче «Простые числа» (см. ссылку на
задачи для подготовки к олимпиаде по программированию). Главное в этой задаче –
разобрать число на составляющие его цифры. Это можно сделать, выполняя
арифметические действия (выполняя деление и анализируя остаток). Но в
программировании классическим решением этой задачи является перевод числовой
переменной в строковую, каждый символ которого доступен как элемент массива. Так как
в задаче не уточняется, какого рода число вводится, можно было написать программу
для анализа целого числа. Она достаточно проста. Например:
var a,z,i, code, max: integer;
s: string;
b: array[0..9] of integer;
begin
read(a);
str(a:5, s);
for i:=1 to length(s) do begin
val(s[i],z, code);
b[z] := b[z] + 1;
end;
max:= b[0];
for i:= 1 to 9 do
if b[i] > max then
max:= b[i];
for i:= 0 to 9 do
if b[i] = max then
write(i,' ');
write(max,'(raz)');
end.
Если на входе –действительное число, то программа усложняется, так как необходимо
игнорировать нули справа, после запятой и значащих цифр. Это можно реализовать так
(решение победителя Филиппова Д.):
var a: real;
s: string;
b: array[0..9] of shortint;
z: shortint;
i, code, max: longint;
k: boolean;
begin
2
read(a);
str(a:0:100, s);
k:= false;
for i:= length(s) downto 1 do begin
if (k = false) and (s[i] <> '0') then
k := true;
if (k = true) and (s[i] <> '.') then begin
val(s[i],z, code);
b[z] := b[z] + 1;
end;
end;
max:= b[0];
for i:= 1 to 9 do
if b[i] > max then
max:= b[i];
for i:= 0 to 9 do
if b[i] = max then
write(i,' ');
write(max);
end.
Задача №3.(3 балла)
Найти все числа, на которые натуральное число n делится с остатком q.
Тест 1 (1 балл)
input.txt:
17 0
output.txt:
1 17
Тест 2 (2 балла)
input.txt:
33 3
output.txt:
5 6 10 15 30
Решение:
Очень простая задача, практически такая же, как задача «Делители» » (см. ссылку на
задачи для подготовке к олимпиаде по программированию)
Например, программу можно написать так (решение победителя Филиппова Д.):
var n, q, i: longint;
begin
read(n, q);
for i:= n downto 1 do
if n mod i = q then
write(i,' ');
end.
Задача №4.(7 баллов)
Маршрут движения автомобиля задан в виде координат вершин ломаной. Необходимо
определить количество правых поворотов. Автомобиль начинает движение из первой
вершины ломаной.
Формат входных данных:
3
Первая строка входных данных состоит из одного числа, количества звеньев ломаной; в
последующих строках - пары натуральных чисел, координаты вершин ломаной.
Формат выходных данных:
одно число - количество правых поворотов
Тест 1 (3 балла)
input.txt:
4
11
22
32
33
43
output.txt:
2
Тест 2 (4 балла)
input.txt:
5
11
12
23
32
11
11
output.txt:
4
Решение:
Задача на разработку геометрического алгоритма: С какой стороны вектора лежит точка?
Если vector(a) и vector(b) - вектора a и b соответственно, то их векторное произведение
vector(a)*vector(b) = ax*by - ay*bx = a*b*sin(beta-alfa), где
ax,ay,bx,by - координаты концов векторов
a - длина вектора a
b - длина вектора b
alfa - угол альфа для вектора a
beta - угол бета для вектора b
Вывод: при общей начальной точке двух
векторов их векторное произведение
больше нуля, если второй вектор
направлен влево от первого, и меньше
нуля, если вправо.
Если известны две точки, то вектор,
основанный на них можно получить
вычитанием двух векторов направленных
из начала координат: например, есть точка A и точка B
вектор|AB| = Вектор|B| - Вектор|A|, иным словом AB_x = Bx-Ax, AB_y= By-Ay
Таким образом, для каждой следующей точки траектории с координатами (px,py) и
вектора |AB|, заданного координатами (ax,ay) и (bx,by), при повороте направо
(bx-ax)*(py-ay)-(by-ay)*(px-ax)<0 . Осталось посчитать число поворотов.
4
Задача №5.(6 баллов)
Вывести на экран целое число 2n, n<=10000, n - натуральное. Входные данные содержат
число n.
Тест 1 (2 балла)
input.txt:
1
output.txt:
2
Тест 2 (4 балла)
input.txt:
50
output.txt:
1125899906842624
Тест 3 (дополнительный)
input.txt:
1000
output.txt:
1071508607186267320948425049060001810561404811705533607443750388370351051
1249361224931983788156958581275946729175531468251871452856923140435984577
5746985748039345677748242309854210746050623711418779541821530464749835819
4126739876755916554394607706291457119647768654216766042983165262438683720
5668069376
Решение.
В данной задаче результат должен быть целым и содержать все цифры числа. Однако,
даже при n=50, все цифры числа не помещаются ни в одном обычно используемом типе
данных. Поэтому предполагается, что программист организует возведение в степень
последовательным умножением, располагая цифры числа в массиве. Если при умножении
в каком-то разряде (элементе массива) получается число больше 9, в данном разряде
оставляют единицы, а его десятки прибавляются к следующему разряду:
const lim = 3500;
var i, j,n: integer;
a: array[1..lim] of byte;
per: byte;
k:boolean;
begin
read(n);
if n=0 then a[lim]:=1 else a[lim]:=2;
if n > 1 then
begin
for i:= 1 to n - 1 do
for j:= 1 to lim do
begin
a[j]:= a[j] * 2;
if a[j] >= 10 then
begin
per:= 1;
a[j]:= a[j] mod 10
5
end;
if per = 1 then
begin
a[j-1]:= a[j-1] + 1;
per:= 0;
end;
end;
end;
k:= false;
for j:= 1 to lim do
begin
if((k= false)and(a[j]<>0)) then k:= true;
if(k) then write( a[j]:1);
end;
writeln;
end.
6
Download