Олимпиада 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