Научная статья на тему 'Разбор задач второй Всероссийской олимпиады по информатике зато'

Разбор задач второй Всероссийской олимпиады по информатике зато Текст научной статьи по специальности «Компьютерные и информационные науки»

CC BY
816
56
i Надоели баннеры? Вы всегда можете отключить рекламу.

Аннотация научной статьи по компьютерным и информационным наукам, автор научной работы — Маврин Павел Юрьевич

Приводится подробный разбор пяти задач по схеме: условие входные данные выходные данные решение. Приводятся полные тексты программ, решающих предложенные задачи.

i Надоели баннеры? Вы всегда можете отключить рекламу.
iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.
i Надоели баннеры? Вы всегда можете отключить рекламу.

Текст научной работы на тему «Разбор задач второй Всероссийской олимпиады по информатике зато»

Маврин Павел Юрьевич

РАЗБОР ЗАДАЧ ВТОРОЙ ВСЕРОССИЙСКОЙ ОЛИМПИАДЫ ПО ИНФОРМАТИКЕ ЗАТО

ЗАДАЧА А. ТАМОЖНЯ

Идет 2163 год. Мишу, который работает в отделении таможни при космодроме города Нью-Питер, вызвал в кабинет шеф.

Как оказалось, недавно Министерство Налогов и Сборов выделило отделению определенную сумму денег на установку новых аппаратов для автоматического досмотра грузов. Естественно, средства были выделены с таким расчетом, чтобы грузы теперь находились на таможне ровно столько времени, сколько требуется непосредственно на их досмотр.

В руках шефа каким-то образом оказались сведения о надвигающейся ревизии -список из N грузов, которые будут контролироваться Министерством. Для каждого груза известны время его прибытия, отсчитываемое с некоторого момента, хранимого в большом секрете, и время, требуемое аппарату для обработки этого груза. Шеф дал Мише задание по этим данным определить, какое минимальное количество аппаратов необходимо заказать на заводе, чтобы все грузы Министерства начинали досматриваться сразу после прибытия. Необходимо учесть, что конструкция тех аппаратов, которые было решено установить, не позволяет обрабатывать два груза одновременно на одном аппарате. Напишите программу, которая поможет Мише справиться с его задачей.

Формат входных данных На первой строке входного файла задано число N (0 < N < 50000). На следующих N строках находится по 2 целых положительных числа Т1 и Ц - время прибытия соответствующего груза и время, требуемое для его обработки (1 < Т < 106, 1 < Ц < 106).

Формат входных данных В выходной файл выведите одно число - наименьшее количество аппаратов, которое нужно установить, чтобы не вызвать подозрений у Министерства.

Пример

customs.in customs.out

3 2

3 2

4 2

5 2

5 3

13 4

15 1

11 5

12 3

10 3

Решение

Необходимое количество аппаратов равно максимальному количеству грузов, проверяемых одновременно. Как найти момент времени, в который проверятся наибольшее количество грузов? Это количество установится после того, как на проверку придет один из грузов. Будем перебирать такие моменты в порядке их возникновения. При этом мы можем быстро пересчитывать количество обрабатываемых грузов при помощи структуры «куча» (также называется «пирамида», подробнее об этой структуре можно прочитать в [1]), которая позволяет находить и удалять минимум N хра-

нящихся в ней элементов за время O (log N). Поместим все грузы, находящиеся на обработке в данный момент в кучу по времени окончания обработки, теперь перед проверкой очередного момента прибытия будем удалять из кучи грузы, обработка которых завершится до того, как поступит этот груз. После этого добавим новый груз в кучу и сравним счетчик с максимумом.

Программа

Для сортировки грузов по времени прибытия используем быструю сортировку, подробное описание которой также можно найти в [1]:

procedure sort(ll, rr : integer); var i, j, m, y : integer; begin

m := t[ll + random(rr - ll + 1)]; i := ll; j := rr; while i <= j do begin

while t[i] < m do inc(i); while t[j] > m do dec(j); if i <= j then begin

У := t[i]; t[i] := t[j]; t[j] := y; У := l[i]; l[i] := l[j]; l[j] := y;

inc(i); dec(j);

end; end;

if i < rr then sort(i, rr); if ll < j then sort(ll, j); end;

Далее реализуем процедуры добавления элемента и удаления минимума для кучи:

procedure add(x : integer); var i, y : integer; begin

inc(nh); heap[nh] := x; i := nh;

while heap[i] < heap[i div 2] do begin

y := heap[i];

heap[i] := heap[i div 2]; heap[i div 2] := y; i := i div 2; end; end;

procedure extract_min; var i, y : integer; begin

heap[1] := heap[nh]; dec(nh); i := 1;

while (i * 2 <= nh) do begin

if i*2 = nh then begin

if heap[i] > heap[i*2] then begin

y := heap[i]; heap[i] := heap[i*2]; heap[i*2] := y; end; exit; end else begin

if heap[i*2]<heap[i*2+1] then begin

if heap[i] > heap[i*2] then begin

y := heap[i]; heap[i] := heap[i*2]; heap[i*2] := y; i := i * 2; end else exit; end else begin

if heap [i] > heap[i*2+1] then begin

y := heap[i]; heap[i] := heap[i*2+1]; heap[i*2+1] := y; i := i * 2 + 1; end else exit; end; end; end; end;

Теперь главная часть программы выглядит совсем просто:

Сортируем грузы: sort(1, n);

Инициализируем кучу:

nh := 0;

h[0] := -1000000000;

Теперь для каждого груза от 1 до n делаем следующее:

Удаляем из кучи все грузы, проверка которых уже закончена:

while (nh > 0) and (heap[1] <= t[i]) do extract_min;

Теперь заносим в кучу новый груз в

кучу:

add(t[i] + l[i]);

И сравниваем счетчик с максимумом: if best < nh then best := nh;

ЗАДАЧА B. ДОМИНОШКИ

Дан прямоугольник N X M. Требуется узнать, можно ли его разбить на доминошки (фигуры 1 X 2 или 2 X 1).

Формат входных данных

Входной файл содержит два натуральных числа N и M (1 < N, M < 10000).

Формат входных данных

В выходной файл выведите «YES» (без кавычек), если прямоугольник NX M можно разбить на доминошки, «NO» (без кавычек) в противном случае.

Пример

domino.in domino. out

3 3 NO

2 2 YES

Решение

Задача решается совсем просто: если одно из чисел четно, то, направив все доминошки вдоль этой стороны прямоугольника, получим искомое замощение. Если же оба числа нечетные, то общее количество клеток ИМ тоже нечетное, следовательно,

его нельзя покрыть доминошками из двух клеток.

Программа read(n, m);

if (n mod 2 = 0) or (m mod 2 = 0) then

writeln('YES') else

writeln('NO');

ЗАДАЧА C. МАТРИЦА

Дан прямоугольник N X М, в каждой клетке которого стоит целое число. Затем с каждой строкой Петя делает следующее: сначала находит в ней максимум. Затем стирает все числа в этой строке, равные ему (в том числе и его самого). В результате этого получается новая строка, которая записывается обратно в прямоугольник. После этого, если в получившейся строке меньше чем г чисел (где г - номер строки), то строка полностью заполняется нулями, иначе начиная с г-ой позиции обратно выписываются стертые максимумы, а все остальное сдвигается вправо.

Например, если на первом шаге была строчка 1 3 2 3, то максимум в ней - 3. Он стирается. Получается строчка 1 2. Далее начиная с первой позиции вставляется 3 3. Получается 3 3 1 2. По данному прямоугольнику требуется вывести результат применения к нему данных операций.

Формат входных данных

Первая строка входного файла содержит два натуральных числа N и М (1 < И, М < 100) Далее идет N строк по М целых чисел в каждой. (Все числа по модулю не превосходят 106).

Формат входных данных

В выходной файл выведите результат применения этих действий.

Пример

matrix.in matrix.out

3 4 3 3 3 1

1 3 3 3 0 0 0 0

4 4 4 4 1 4 2 3

1 2 3 4

Решение

В этой задаче не требуется придумывать сложных алгоритмов, нужно просто аккуратно сделать то, что написано в условии задачи.

Программа

Для каждой строки i делаем следующее:

Находим максмум:

mx := a[i, 1]; for j := 1 to m do

if a[i, j] > mx then mx := a[i, j];

Находим количество элементов, оставшихся после удаления максимумов: k := 0;

for j := 1 to m do

if a[i, j] <> mx then inc(k);

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Если их меньше i, то заполняем строку нулями:

if k < i then

for j := 1 to m do a[i, j] := 0;

Иначе сдвигаем эти элементы к левому краю: k := 0;

for j := 1 to m do if a[i, j] <> mx then begin inc(k);

a[i, k] := a[i, j]; end;

Теперь освобождаем место для вставки максимумов, сдвигая нужное число элементов к правому краю:

q1 := k; q2 := m;

while q1 >= i do begin

a[i, q2] := a[i, q1]; dec(q1); dec(q2); end;

А на освободившееся место вставляем максимумы:

for j := i to i + m - k - 1 do

a[i, j] := mx;

ЗАДАЧА D. ЕДИНИЦЫ

чЙЙЙУ!

Найдите квадрат числа, десятичная запись которого состоит из п единиц.

Формат входных данных Входной файл содержит единственное число п (1 < п < 105).

Формат входных данных Выведите искомый квадрат.

Пример

ones.in ones.out

2 121

9 12345678987654321

Решение

Число, десятичная запись которого состоит из n единиц очевидно равно (10й - 1)/ 9, тогда его квадрат равен (10й - 1)2 / 81. Несложно убедиться, что число (10й - 1)2 имеет следующую структуру: 99...9800...1 (число девяток и нулей равно (n - 1)). Теперь, зная это число, можно воспользоваться стандартным алгоритмом деления числа «уголком» на 81 и получить искомое.

Программа r := 0;

for i := 1 to 2*n do begin

r := r * 10;

if i < n then r := r + 9 else if i = n then r := r + 8 else if i = 2*n then r := r +1; if i > 1 then

write (chr (ord( '0') + (r div 81))) r := r mod 81; end;

ЗАДАЧА E. СУММА

Дано два натуральных числа, найдите их сумму.

Формат входных данных Входной файл содержит два натуральных числа а и Ь (1 < а, Ь < 10100).

Формат входных данных Выведите в выходной файл искомую сумму без ведущих нулей.

Решение

Поскольку числа а и Ь не умещаются ни в один из стандартных типов, приходит-

ся действовать сложнее. Запишем эти числа в массивы, по одной цифре в ячейку, после чего используем обычный алгоритм сложения чисел «в столбик».

Программа

Прочитаем данные числа в строки, после чего запишем их по цифрам в массивы (цифры заносятся в массив, начиная с последней):

for i := 1 to length(s) do a[i] := ord(s[length(s) - i + 1]) - ord('O'); j := 0;

Теперь сложим эти числа, занося результат в массив с: j := 0;

for i := 1 to 101 do begin

j := j div 10 + a[i] + b[i]; c[i] := j mod 10; end;

Осталось вывести результат, пропустив ведущие нули: j := 101;

while (c [ j ] = 0) and (j > 1) do dec(j);

for i := j downto 1 do write(c[i]) ;

Замечание: Для всех задач ограничение по времени - 2 секунды, ограничение по памяти - 8 мегабайт.

Пример

sum.in sum. out

361 239 600

Литература

1. Вирт Н. Алгоритмы и структуры данных. СПб.: «Невский диалект», 2001.

© Наши авторы, 2004. Our authors, 2004.

Маврин Павел Юрьевич, студент 2 курса СПбГУ ИТМО.

i Надоели баннеры? Вы всегда можете отключить рекламу.