acm.timus.ru №2002. Тестовое задание

Автор задачи: Кирилл Бороздин
Источник задачи: Уральская региональная командная олимпиада по программированию 2013

Ограничения:

Время: 0.5 секунды
Память 64 Мб

Условие

Это было обычное хмурое октябрьское утро. Небо было затянуто тяжёлыми серыми тучами, накрапывал дождь. Капли падали на стёкла автомобилей, били в окна домов. Илья сидел за компьютером и угрюмо взирал на унылый пейзаж за окном. Внезапно его взгляд привлекла надпись, появившаяся в правом нижнем углу экрана: «You have 1 unread email message(s)». Заранее приготовившись удалить бесполезный спам, Илья открыл письмо. Однако оно оказалось куда интереснее…
Вас приветствует отдел по работе с персоналом компании «Рутнок БКС»!
Мы рассмотрели вашу заявку на вакансию разработчика программного обеспечения и были заинтересованы вашей кандидатурой. Для оценки ваших профессиональных навыков мы предлагаем вам выполнить несложное тестовое задание: необходимо реализовать систему регистрации для форума. Она должна поддерживать три операции:
  1. «register username password» — зарегистрировать нового пользователя с именем «username» и установить для него пароль «password». Если такой пользователь уже есть в базе данных, необходимо выдать ошибку «fail: user already exists». Иначе нужно вывести сообщение «success: new user added».
  2. «login username password» — войти в систему от имени пользователя «username» с паролем «password». Если такого пользователя не существует в базе данных, необходимо выдать «fail: no such user». Иначе, если был введен неправильный пароль, нужно выдать «fail: incorrect password». Иначе, если пользователь уже находится в системе в данный момент, необходимо вывести «fail: already logged in». Иначе нужно вывести сообщение «success: user logged in».
  3. «logout username» — выйти из системы пользователем «username». Если такого пользователя не существует, необходимо вывести «fail: no such user». Иначе, если пользователь не находится в системе в данный момент, следует выдать «fail: already logged out». Иначе необходимо выдать сообщение «success: user logged out».
Пользуйтесь этим письмом как формальным описанием алгоритма и строго соблюдайте порядок обработки ошибок. Желаем вам удачи!
И вот Илья, откинув все дела, уже решает тестовое задание. Попробуйте и вы выполнить его!

Исходные данные

В первой строке дано целое число [latex]n[/latex] — количество операций [latex]1\leq{n}\leq100[/latex]. В каждой из следующих [latex]n[/latex] строк содержится один запрос в соответствии с форматом, описанным выше. В качестве «username» и «password» могут выступать любые непустые строки длиной до 30 символов включительно. Строки могут состоять только из символов с кодами от 33 до 126.

Результат

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

Пример

Исходные данные Результат
6

register vasya 12345

login vasya 1234

login vasya 12345

login anakin C-3PO

logout vasya

logout vasya

success: new user added

fail: incorrect password

success: user logged in

fail: no such user

success: user logged out

fail: already logged out

Решение

Для решения данной задачи нам необходимо воспользоваться структурой данных, которая хранит в себе пары вида «ключ — значение», а также структурой, которая будет хранить в себе некоторое множество. Воспользуемся структурами HashMap (Java) / map (C++) (key -> value)  и HashSet  (множество).

Рассмотрим операции, которые должна уметь обрабатывать наша система:

  1. «register username password». При регистрации нового пользователя будем помещать его в нашу «базу» зарегистрированных пользователей при условии, что он не зарегистрирован. Поиском по ключу в HashMap / map проверим существование уже зарегистрированного никнейма. Если найдётся такой пользователь, то система выдаст сообщение об ошибке.
  2. «login user password». Если база пользователей содержит в себе логин пользователя, пароли совпадают и пользователь не в он-лайне, то система разрешит user’у вход на форум. В противном случае, с соответствующими сообщениями об ошибках, не разрешит вход. Отслеживать пользователей, которые уже online, будем с помощью HashSet. Если пользователя нет в базе пользователей, которые сейчас на сайте, то открывая доступ, система поместит его в базу-online. Тогда новый запрос login с этого ника будет отклонён.
  3. «logout name». Если пользователя нет в базе пользователей, то его logout невозможен. Иначе, если его нет в базе-online, то тоже система выдаст сообщение об ошибке. Если user есть в базе пользователей и находится в онлайне, то выход возможен. Во время logouta удаляем пользователя из базы-online.

Реализация

В данном отчёте задачи будут представлены на языках Java и C++. Опишем, для начала, какие классы и методы необходимо использовать для решения этой задачи на языке Java:

HashMap:

Будем использовать интерфейс Map, имплементация (реализация) — HashMap. Из интерфейса Map воспользуемся следующими методами:

  • containsKey(Key K) — возвращает true, если ключ найден. В противном случае — false;
  • put(Key K, Value V) — записывает пару ключ-значение в структуру;
  • get(Key K) — по ключу возвращает значение.

HashSet:

Используем интерфейс Set, реализация — HashSet. Будем использовать следующие методы:

  • contains(Object o) — возвращает true, если элемент принадлежит множеству. Иначе — false;
  • add(Object o) — добавляет элемент во множество;
  • remove(Object o) — удаляет элемент из множества.

Теперь для С++:

В С++ воспользуемся немного другим подходом. Воспользуемся только map. Создадим структуру, которая будет содержать 2 поля: пароль и статус. Воспользуемся следующими методами:

  • find (K key) — возвращает итератор элемента.
  • end() — возвращает итератор за последним элементом.

set или без него?

Для данной задачи использование set’a не принципиально. Но если предположить, что, помимо запросов регистрации, входа и выхода, был бы ещё и запрос вывести пользователей, которые онлайн, преимущество использования set’a очевидно.

Код на Java: 

Код на С++:

 

Результаты

Обе реализации прошли все тесты на Тимусе с такими результатами:

Язык Время работы Память
С++ 0.015 412 КБ
Java 0.124 1 804 КБ

Ссылки

Задача

Ideone (Java)

Ideone (C++)

Java (Set)

Java (Map)

C++ (map)

C++ (set)

Related Images:

А1033

Условие

Получить все размещения из [latex]9[/latex] элементов [latex]\left\{1,2, \ldots, 9\right\}[/latex] по [latex]5[/latex] элементов в каждом.

Код на С++

 

Код на Java:

 

Решение

При решении этой задачи мне понадобились 2 источника информации:

Там были приведены алгоритмы генерирования перестановок («Комбинаторные алгоритмы», стр. 27-29) и генерирования сочетаний («Комбинаторика для программистов», стр. 39-41).
Размещения я получал следующим образом:

  • Посчитал кол-во всевозможных размещений по формуле [latex]A^{k}_{n}=\frac{n!}{(n-k)!}=\frac{9!}{4!}=15120[/latex];
  • Заметил, что размещения — это перестановки всех уникальных комбинаций из 5 чисел (т.е сочетаний);
  • Поскольку кол-во перестановок [latex]P_{k}=k![/latex], а кол-во сочетаний — [latex]C_{n}^{k}=\frac{n!}{k!(n-k)!}[/latex], то кол-во размещений [latex]A_{n}^{k}=P_{k}\times{C_{n}^{k}}=\frac{n!k!}{k!(n-k)!}=\frac{n!}{(n-k)!}=15120[/latex];

Таким образом, генерируя вначале сочетание, я генерировал перестановки этого сочетания. В результате вышло 15120 размещений.

Related Images:

e-olymp 4850. Шайтан-машинка

Условие

У Ибрагима есть магическая чёрная шайтан-машинка. На ней есть три кнопки и табло. Табло может показывать не более чем четырёхзначные числа. Каждая из кнопок меняет число некоторым образом: первая домножает его на [latex]3[/latex], вторая прибавляет к нему сумму его цифр, а третья вычитает из него [latex]2[/latex]. В случае, если число становится отрицательным или превосходит [latex]9999[/latex], шайтан-машинка ломается.

Ибрагим может нажимать кнопки в любом порядке. Его интересует, как ему получить на табло число [latex]b[/latex] после некоторой последовательности нажатий, если сейчас шайтан-машинка показывает [latex]a[/latex]. Помогите ему найти минимальное необходимое число нажатий.

Входные данные

В одной строке находится два натуральных числа [latex]a[/latex] и [latex]b[/latex] latex[/latex].

Выходные данные

Вывести минимальное необходимое количество действий.

Задача
Зачтённое решение

Код

Ideone

Код на Java:

 

Решение

Для решения данной задачи я решил использовать алгоритм BFS (поиск в ширину). Обычно, данный алгоритм применяется для поиска пути от одной вершины к другой, причём длина пути должна быть минимальной.

Всю «карту» расположения операций можно представить в виде графа-дерева, где от каждой вершины отходят максимум 3 ребра (в каждой вершине по операции, проделанной со значением вершины, которая находится на уровень выше). Будем рассматривать каждую вершину. Если исходная вершина и есть конечной, то выходим из программы с вердиктом «0». Иначе будем поочерёдно рассматривать все вершины. Заведём массив расстояний, в котором предположим, что расстояние до нужной нам вершины равно 1. С проходом каждой вершины будем подсчитывать расстояние до нужной нам вершины (прибавляя к расстоянию 1), в которую мы рано или поздно попадём.

Related Images:

e-olimp 5080. Количество висячих вершин 1

Код: 

 

 

Related Images:

AA17

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

Решение: Заводим цикл от первого символа, в цикле сравниваем каждый символ с предыдущим. Если они совпадают — удаляем один из них.

Код C++:

Код Java:

 

Тесты:

Строка Результат
aassddff asdf
1122345566 123456

Related Images:

Ю12.19

Задача:  В имеющемся словаре найти группы слов, записанных одними и теми же буквами и отличающиеся только их порядком, то есть перестановкой, например, (КОРМА, КОМАР).

Код:

 

Тесты:

Исходный словарь Обработанный словарь
the and a to I is of have you he it in not was that his do on with she at say her for as are we but can him they up what out me go get this from be look my there know all one no see will back into like if were then an come think so down your them would about man take just by am now over make been or time when hand who want here tell off right their turn two through eye head other how some more around door room face day where way night well thing open away give only something ask move stand good find again little try too still hear walk before leave sit let long call feel close very why which car any hold work run never start even light than after put yes stop old watch first may talk another cut mean pull behind smile our toward towards much its house keep place begin nothing year woman side because three seem wait need moment himself stare arm use voice last late across sure front sound big really name should new anything against guy kill point small happen wall black step window life maybe fall own far under boy

no
on
three
there
own
now
how
who
thing
night
its
sit
name
mean

Все слова Безымянный

Алгоритм:

Для решения данной задачи я воспользовался возможностью, которую мне предоставляет библиотека <algorithm> . Поскольку мне надо было проверить, являются ли строки перестановками строки s_tmp, которую я ставлю в роли исходной с каждой итерацией, я воспользовался функцией is_permutation .  Если некая строка является перестановкой, то она выводится на экран и стирается. С последующими итерациями будет проводится проверка на наличие на том или ином месте строки. Если строки обнаружено не будет, программа перейдёт к следующей итерации.

Для проверки правильности работы программы, воспользуйтесь ссылкой .

UPD: Поскольку я понял, что вводить вначале количество слов неудобно, я решил написать функцию, которая сама создаст массив из введённой мной строкой.

Related Images:

А410б

Задача: Дана целочисленная матрица [latex][a_{i,j},\ i=1,\ldots,n;\ j=1,\ldots,m][/latex]. Получить [latex]b_{1},\ldots,b_{n}[/latex], где

[latex]{b}_{i}=\sum_{j=1}^{n}(-1)^{i+j}a_{ij}[/latex]

Код на С++: 

 

Код на Java:

 

 

Тесты: 

[latex]n*m[/latex] [latex]\begin{bmatrix}{a}_{ij}\end{bmatrix}[/latex] [latex]b_{i}[/latex]
3*3 1 2 3

4 5 6

7 8 9

2 -5 8
1*6 2 -4 6 -8 10 -12 42
3*5 1 3 5 7 9

11 13 15 17 19

21 23 25 27 29

5 -15 25

Алгоритм:  Чтобы решить эту задачу, необходимо было создать два массива: входной массив (матрицу) и массив результатов (который надо инициализировать нулями). Далее, необходимо завести цикл, в котором будет проводится, собственно говоря, подсчёт. В зависимости от суммы номеров строки и столбца исходной матрицы, -1 в степени этой суммы будет принимать положительное  или отрицательное  значение. Соответственно, к результату будет прибавляться или отниматься значение, стоящее на i-том j-том месте.

Для проверки правильности работы программы, воспользуйтесь ссылкой.

Related Images:

А137а

 

Задача:  Даны натуральное число [latex]n[/latex] и действительные числа [latex]a_{1},\ldots,a_{n}[/latex].

Вычислить:

[latex]a_{1},a_{1}+a_{2},\ldots,a_{1}+a_{2}+\ldots+a_{n}[/latex].

Тесты: 

Кол-во элементов [latex]n[/latex] [latex]a_{1},a_{2},\ldots,a_{n}[/latex] result в каждой итерации
7 1, 2, 3, 4, 5, 6, 7 1, 3, 6, 10, 15, 21, 28
10 10, 12, 14, 16, 18, 20, 21, 23, 25, 27 10, 22, 36, 52, 70, 90, 111, 134, 159, 186
5 0.1, 0.2, 0.3, 0.4, 0.5 0.1, 0.3, 0.6, 1.0, 1.5
5 -1, -2, 3, 4, -5 -1, -3, 0, 4, -1

Код на С++: 

 

Код на Java:

 

Решение:  Для подсчёта суммы в данной задаче надо было организовать цикл for (поскольку указано количество элементов в ряду), и с каждой итерацией прибавлять к результату result (которому предварительно придано значение 0) введённое с клавиатуры значение, потом выводить результат на экран.

Для проверки правильности работы программы, воспользуйтесь ссылкой.

Related Images:

А116а

Задача: Даны натуральное число [latex]n[/latex] и действительное [latex]x[/latex]. Найти:

[latex]\sum_{i=1}^{n}\frac{x^{i}}{i!}[/latex]

Тесты:

Число [latex]x[/latex], возводимое в степень Кол-во шагов [latex]n[/latex] Результат result
5 3 38.(3)
4 12 53.5832
20 5 34886.7
0 0 0
10 10 12841.3

Решение: Для решения данной задачи надо было провести численный анализ. Каждый раз высчитывать и прибавлять результат нельзя, т.к программа будет работать очень долго. По-этому стоит рассмотреть два значения: текущее и последующее, [latex]x_{n}[/latex] и [latex]x_{n+1}[/latex]. Поделим одно на другое:

[latex]\frac{x_{n+1}}{x_{n}}=\frac{x^{i+1}*i!}{(i+1)*i!*x^{i}}=\frac{x}{i+1}[/latex]

Поскольку сумму ряда считаем с 1, то делить будем на [latex]i[/latex], а не на [latex](i+1)[/latex].

Код на С++: 

 

Код на Java:

 

 

Для проверки правильности работы кода, воспользуйтесь ссылкой.

Related Images:

Ю4.18

Задача: В массиве [latex]Z(2n)[/latex] каждый элемент с чётным индексом поменять местами с предыдущим, то есть получить последовательность чисел [latex]z_{2}[/latex], [latex]z_{1}[/latex], [latex]z_{4}[/latex], [latex]z_{3}[/latex], \ldots ,[latex]z_{2n}[/latex], [latex]z_{2n-1}[/latex].

Тесты: 

[latex]n[/latex] Входной массив Обработанный массив
5 1 2 3 4 5 6 7 8 9 10 2 1 4 3 6 5 8 7 10 9
7 2 4 6 8 10 12 14 16 18 20 22 24 26 28 4 2 8 6 12 10 16 14 20 18 24 22 28 26

Код на С++: 

Код на Java:

 

 

Решение:  Для того, чтобы поменять местами чётный и нечётный по порядковому номеру элементы массива, надо определить чётность порядкового номера. Для этого надо проверить остаток от деления на 2, т.е если [latex]imod2=0[/latex], то меняем предыдущий элемент с текущим.

Для проверки правильности работы программы, воспользуйтесь ссылкой.

Related Images:

Ю3.20

Задача: Для заданных [latex]a[/latex] и [latex]p[/latex] вычислить [latex]x = \sqrt[p]{a}[/latex] по рекуррентному соотношению Ньютона: 

[latex]x_{n+1}=\frac{1}{p}*\left[(p-1)x_{n}+\frac{a}{x_{n}^{p-1}}\right][/latex]  [latex]x_{0} = a[/latex]

Сколько итераций надо выполнить, чтобы для достижения заданной погрешности [latex]\varepsilon[/latex] выполнялось соотношение:

[latex]\left|x_{n+1}-x_{n}\leq\varepsilon\right|[/latex]?

Тесты:

[latex]a[/latex] [latex]p[/latex] Значение корня [latex]x[/latex] Значение корня [latex]x[/latex], подсчитанного с помощью соотношения Количество итераций
57 5  2.24479 2.24479  18
16 2 4 4 5
230 2  15.1658  15.1658 7
9 3  2.08008 2.08008  7

Код на С++: 

Код на Java:

 

 

Решение: Для подсчёта значения корня с помощью рекуррентного соотношения, я создал цикл, в котором организовал подсчёт значения таким образом, что пока разница значения корня x, подсчитанного с помощью функции pow, cо значением текущего корня xn,  подсчитанным с помощью соотношения, больше заданной погрешности eps, то, записывая текущее значение в переменную x_prev, подсчитываю новое значение корня. В зависимости от заданной погрешности, программа считает результат и выводит его на экран вместе с кол-вом итераций.

UPD: По предложению Игоря Евгеньевича добавил быстрое возведение в целую степень.

Решение UPD: Чтобы построить алгоритм быстрого возведения в степень, необходимо рассмотреть две ситуации:

  1. Когда степень чётна;
  2. Когда степень не чётна;

Ситуация 1 : Проведя несложный анализ  можно заметить, что [latex]{a}^{p}[/latex] можно представить в виде

[latex](a^{\frac{p}{2}})^{2}[/latex].

Ситуация 2: В этой ситуации необходимо перейти в степень [latex]p-1[/latex], которая является чётной.

[latex]a^{p}=a^{p-1} * a[/latex]

И в результате получим алгоритм, который работает за [latex]O(\log n)[/latex].

 

Проверить правильность работы программы можно здесь (UPD):  http://ideone.com/VBLGKO

 

Related Images:

А60б

Задача:  Пусть [latex]D[/latex] — заштрихованная часть плоскости и пусть [latex]u[/latex] определяется по [latex]x[/latex] и [latex]y[/latex] следующим образом ( запись [latex](x, y)\epsilon D[/latex] означает, что точка с координатами [latex]x[/latex], [latex]y[/latex] принадлежит [latex]D[/latex]):

[latex]u=\left\{\begin{matrix}-3, \text{if} (x, y)\epsilon D\\ y^{2} \end{matrix}\right.[/latex]

Даны действительные числа [latex]x[/latex] и [latex]y[/latex]. Определить  [latex]u[/latex].

Код на С++:

 

Тесты:

[latex]x[/latex] [latex]y[/latex] Результат

[latex]u[/latex]

[latex]0[/latex] [latex]0[/latex] [latex]-3[/latex]
[latex]0[/latex] [latex]1[/latex] [latex]1. 00[/latex]
[latex]1[/latex] [latex]0[/latex] [latex]-3[/latex]
[latex]-1[/latex] [latex]0[/latex] [latex]0. 00[/latex]
[latex]0[/latex] [latex]-1[/latex] [latex]-3[/latex]
[latex]0,6[/latex] [latex]0,8[/latex] [latex]0. 64[/latex]
[latex]0,5[/latex] [latex]-0,5[/latex] [latex]-3[/latex]

 

Код на Java:

 

 

Безымянный

Для того, чтобы определить находится ли нужная точка с координатами [latex](x,y)[/latex] в заштрихованной части графика, нужно задать такое условие, чтобы эта точка находилась в круге [latex]x^{2}+y^{2}=1[/latex] и была ниже прямой [latex]y=\frac{x}{2}[/latex].

Отсюда следует, что если [latex]x^{2}+y^{2}\leqslant1[/latex] и [latex]y\leqslant\frac{x}{2}[/latex], то точка принадлежит заштрихованной части круга.

Результат [latex]u[/latex] выводится с точностью до двух знаков после запятой.

Запустить код и проверить тесты можно тут: http://ideone.com/N3UoQ7.

Related Images:

Ю1.9

Кубическое уравнение. Заданы три корня кубического уравнения : [latex]x_{1},x_{2},x_{3}[/latex] . Найти коэффициенты этого уравнения.

[latex] x_{1}[/latex] [latex] x_{2}[/latex] [latex] x_{3}[/latex] Результат [latex]b[/latex] Результат [latex] c[/latex] Результат [latex] d[/latex] Комментарий:
 1  2  3  -6.00  11.00  -6.00 Тест пройден
0.5  6  0.78  -7.28 8.07  -2.34 Тест пройден
-1  -2  -2.25  5.25 8.75  4.50 Тест пройден
 -0.24 -1 2.24  -1.00 -2.54  -0,54 Тест пройден

 

 

Дано кубическое уравнение типа [latex](x — x_{1})(x-x_{2})(x-x_{3})=0[/latex]. После недолгих преобразований я получаю такое выражение:

[latex]x^{3}-(x_{1}+x_{2}+x_{3})x^{2}+(x_{1}x_{2}+x_{2}x_{3}+x_{3}x_{1})x-x_{1}x_{2}x_{3}=0[/latex].

Потом присваиваю трём переменным выражения для коэффициентов:

[latex]\begin{cases} & \ x_{1}+x_{2}+x_{3}=-b \\ & \ x_{1}*x_{2}+x_{2}*x_{3}+x_{1}*x_{3}= c \\ & \ x_{1}*x_{2}*x_{3}=-d \end{cases}[/latex]

где [latex]b[/latex] — коэффициент при [latex]x^{2}[/latex], [latex] c[/latex] — при [latex]x[/latex], а [latex] d[/latex] — свободный коэффициент.

 В итоге, все решение задачи свернулось в 3 этапа:

  1. Ввод переменных.
  2. Вычисление коэффициентов.
  3. Вывод результата.

Результат выводится с точностью до двух знаков после запятой.

Для выполнения программы и проверки тестов можно воспользоваться следующим объектом.

Код на языке Java:

 

Related Images: