Всем привет!
30 января, в 6.00 MSK состоится Topcoder SRM 606.
Предлагаю после контеста обсудить здесь задачи.
GL & HF
№ | Пользователь | Рейтинг |
---|---|---|
1 | tourist | 4009 |
2 | jiangly | 3823 |
3 | Benq | 3738 |
4 | Radewoosh | 3633 |
5 | jqdai0815 | 3620 |
6 | orzdevinwang | 3529 |
7 | ecnerwala | 3446 |
8 | Um_nik | 3396 |
9 | ksun48 | 3390 |
10 | gamegame | 3386 |
Страны | Города | Организации | Всё → |
№ | Пользователь | Вклад |
---|---|---|
1 | cry | 167 |
2 | maomao90 | 163 |
2 | Um_nik | 163 |
4 | atcoder_official | 161 |
5 | adamant | 159 |
6 | -is-this-fft- | 158 |
7 | awoo | 157 |
8 | TheScrasse | 154 |
9 | nor | 153 |
9 | Dominater069 | 153 |
Всем привет!
30 января, в 6.00 MSK состоится Topcoder SRM 606.
Предлагаю после контеста обсудить здесь задачи.
GL & HF
Название |
---|
Hm, 3:00 AM here. And I've got two exams later on the same day. Sounds like a challenge... or insanity finally growing unstoppable :D
4:00 AM here. I have an exam too! This is something that should belong to "You know you're a TopCoder when..." :-)
Looks like "insanity" got the best of both of you and you participated despite having exams the next day :)
Yeah, and so far so good — the SRM went well, one exam went well. I hope the luck holds :D
Вот смотришь на некоторые решения по 450 — и, с одной стороны, завидуешь тому, какая богатая у людей фантазия, с другой — не можешь понять, как же эту ересь ломать.
А как она решается?
У меня вообще неприятные ощущения от этой задачи. Это даже не боян, это... Давать такое — моветон. Т.е. задача весьма очевидным способом сводится к "есть ли в массиве число, которое встречается больше N/2 раз, какое это число и сколько раз встречается?", а дальше уже полнейший боян. Эта задача есть на большинстве китайских архивов, есть на тимусе, и, что еще хуже, она очень популярна на собеседованиях в Google и Facebook (ну и подозреваю, что не только там), и есть в большинстве популярных статей и сборников "какие задачи надо уметь решать для собеседования". А эти статьи АСМщики читают, вероятно, чаще чем Кормена)) Я бы сравнил ее с задачей, где просят в массиве найти единственное число, у которого нету пары. И точно так же считаю плохой идеей давать такое на раунд. Ну ладно, это так, мое субъективное мнение, проехали.
А стандартное решение — за О(N) времени и О(1) памяти, идея в нем простая. Заведем стек, рассматривая очередное число — будем добавлять его в стек, если стек пустой или на верхушке стека число, совпадающее с нашим, или же будем удалять верхнее число стека (не добавляя наше) в противоположном случае. Далее можно заметить, что если в этом стеке что-то есть, то это одно и то же число, а не несколько разных, и перейти от стека к паре "значение — сколько раз в стеке", и это дает нам О(1) памяти.
Ключевое наблюдение — в массиве может быть только одно число, у которого больше N/2 повторений, и если такое число есть, то в конце выполнения алгоритма в стеке будет именно это число. Действительно, каждому "недостающему" вхождению этого числа в стэк можно сопоставить какое-то другое число, которым мы "сожгли" наше число (если в какой-то момент оно было в стеке) или которое мы "сожгли" нашим числом (если в момент его рассмотрения в стеке было что-то другое, и мы его так и не добавили). А таких "других чисел" будет меньше, чем вхождений нашего числа (потому что его, по условию, больше половины), следовательно, оно точно должно остаться в стеке хоть в одном экземпляре. А как мы уже знаем, в стеке в каждый момент времени может быть только одно число, а не несколько различных.
Так что первым проходом моделируем этой стек и определяем, что в нем будет после выполнения алгоритма. Это и будет наше "подозрительное" число. Вторым проходом считаем, сколько на самом деле раз встречается подозрительное число, и отсюда получаем ответ.
Дай ссылку на задачу на тимусе.
Как доказать, что если число встречается не больше чем половину раз, то всегда можно разбить на total / 2 пар?
Задачу потом поищу и впишу в правку. Задача на тимусе
Конструктив — возьмем 2 числа, которых сейчас больше всего, создадим из них одну новую пару и перейдем к меньшей задаче. Не сложно показать, что в полученной задаче условие "число встречается не больше, чем половину раз" сохраняется "почти всегда". Если максимум был уникальным, или их было два, то уменьшился на 1 максимум и уменьшилась на 1 сумма без максимума. Если максимумов было больше двух, то единственный случай, когда инвариант нарушится — в случае трех единиц (приняв текущий максимум за k, а сумму всех элементов кроме 3 максимальных за t, получим это из условия k>2k-2+t). Но в этом случае у нас как раз и останется последнее число без пары.
Учитывая, что ее решило только 117 из 514, на боян это мало похоже..
Пусть всего есть N человек. Ключевой момент — все "плохие" пары будут содержать один и тот же элемент (доказывается от противного). Предполагаем, что этот элемент встречается чаще чем N / 2 раз — тогда его можно найти за один проход (выкидываем попарно различные, оставшийся в конце X — наш). Ещё за один проход находим сколько именно раз встретился X — пусть встретился Y раз; если Y <= N / 2, то ответ N / 2, иначе N — Y.
А еще без стека можно, в два прохода. Памяти больше, чем O(1), но зато до такого решения, лично мне, было проще додуматься.
Первый проход, находим самый частый 20-битный префикс:
Второй проход, находим самое частое число:
Максимальное число в D[] — количество вхождений самого частого элемента, если он встречается больше, чем N/2 раз.
Проходит.
Глупый, наверное, вопрос, но как узнать вердикт, если задача не прошла на контесте? Еще интересно, как свой код, написанный на контесте, можно скопировать?
Например, заходишь в свой список контестов, выбираешь последний, при нажатии на имя какого-нибудь класса внизу можно увидеть свой код, если по этой задаче ты хоть что-то комплирововал, и вердикт этого кода, если сабмитил (например, вот так).
Чтобы узнать, к примеру, время выполнения — можешь этот код копирнуть в практис и потестить там.