Переберём количество строк длины p и q в ответе. Пусть это величины a и b. Если a·p + b·q = n, то посторим ответ, откусив с префикса сначала a раз строки длины p, а затем b раз строки длины q. Если ни одной подходящей пары a, b не нашлось, то ответа не существует. Конечно эту задачу можно решать и за линейное время, но здесь это не требовалось, поскольку ограничение на длину строки было маленьким.
Асимптотическая сложность решения: O(n2).
612B - HDD is Outdated Technology
В условии задачи задана перестановка f. Построим по ней другую перестановку p следующим образом: pfi = i. Таким образом, перестановка p определяет номер сектора по номеру фрагмента. Перестановка p называется обратной к перестановке f и обозначается f - 1. Теперь ответ на задачу равен просто .
Асимптотическая сложность решения: O(n).
612C - Replace To Make Regular Bracket Sequence
Заметим, что поскольку мы не можем менять тип скобок, то для существования ответа необходимо, чтобы заданная строка была правильной скобочной последовательностью без учета вида скобок. Если это не так, то ответа не существует. Иначе каждой открывающей скобке соответствует ровно одна закрывающая, и каждой закрывающей — ровно одна открывающаяя. Теперь заметим, что если пара соответствующих друг другу скобок одного вида, то их мы можем не менять. Если же они разного вида, то поменяем вид закрывающей на вид открывающей. Таким образом, мы построим ответ. Легко убедиться, что ответ оптимальный, поскольку задачи для несоответствующих друг другу скобок не связаны друг с другом и могут быть рассмотрены по отдельности.
Единственная техническая тонкость в том как найти соответствующие друг другу скобки. Для этого заведем стек открытых скобок. Теперь будем идти по строке слева направо и если скобка открывающая, то просто добавим ее в стек. Если же она закрывающая, то возникает три случая: 1) стек пуст; 2) вверху стека лежит открывающая скобка того же вида, что и текущая закрывающая; 3) вверху стека скобка вида отличного от текущего. В первом случае ответа не существует, во втором нужно просто выкинуть открывающую скобку из стека, а в третьем нужно выкинуть открывающую скобку из стека и увеличить ответ на единицу.
Асимптотическая сложность решения: O(n).
612D - The Union of k-Segments
Для каждого отрезка создадим два события в момент li — открытие отрезка и в момент ri — закрытие отрезка. Отсортируем все события по моменту времени, при равенстве сначала будем обрабатывать события открытия отрезков. Это можно сделать, например, накидав в vector<pair<int, int>> events (пример для языка C++) пары момент времени и тип события ( - 1 для открытия и + 1 для закрытия). Далее это массив можно отсортировать стандартным компаратором.
Теперь будем идти по массиву events и считать баланс отрезков balance, для этого каждый раз нужно просто из баланса вычесть тип события. Теперь если баланс оказался равен k, а до этого был k - 1 значит мы стоим в левом конце отрезка из ответа, запомним этот левый конец (равный моменту текущего события) в переменную left и будем идти дальше. Если баланс оказался равен k - 1, а до этого был равен k значит мы обнаружили конец некоторого отрезка из ответа right. Добавим в ответ отрезок [left, right]. Таким образом, мы получим непересекающийся набор отрезков, содержащий все покрытые точки, в порядке слева направо. Очевидно он и является ответом на задачу.
Асимптотическая сложность решения: O(nlogn).
612E - Square Root of Permutation
Рассмотрим некоторую перестанову q. Построим по ней ориентированный граф дугами, которого будут (i, qi). Этот граф, как известно, представляет собой набор неперескающихся циклов. Теперь посмотрим, что происходит с этим графом при возведениии перестановки в квадрат: все циклы нечетной длины остаются таковыми (только порядок вершин меняется, происходит чередование через одну вершину), а циклы четной длины разбиваются на два цикла вдвое меньшей длины. Таким образом, чтобы найти корень из перестановки нужно оставить все циклы нечетный длины, прочередовав их в обратном от возведения в квадрат порядке, а циклы четной одинаковой длины нужно разбить на пары и слить в один цикл (если оказывается невозможным разбиение на пары, то ответа не существует).
Асимптотическая сложность решения: O(n).
Авторское решение по этой задаче основано на динамическом программировании. На мой взгляд никакие жадные идеи в этой задаче не работают. Для решения задачи будем считать две динамики z1i — ответ на задачу если все числа меньшие ai уже выведены, а больше либо равные еще нет; и z2i — ответ на задачу если все числа меньше либо равные ai уже выведены, а большие еще нет. Введем обозначение dij — кратчайшее расстояние от i до j на кольце и odij — расстояние от i до j если идти по часовой стрелке. Легко видеть, что z2i = minj(zj + dij), по всем j таким, что aj есть наименьшее число большее ai. Пусть теперь хотим посчитать значение z1i. Рассмотрим все элементы равные ai (в одном из них мы сейчас находимся). Если такой элементв один, то z1i = z2i. Иначе у нас есть два варианта обхода этих элементов: по или против часовой стрелки. Пусть мы идём по часовой стрелке, тогда последним мы выпишем число из ближайшего к i равный элемент против часов стрелке, пусть это элемент u. Иначе последним мы последним посетим ближайший к i элемент по часовой стрелке, пусть это элемент v. Тогда z1i = min(z2u + odiu, z2v + odvi). Теперь легко видеть, что ответ на задачу равен mini(z1i + dsi), по всем i таким, что ai есть наименьший элемент в массиве, а s есть стартовая позиция. Плюс к этому ко всему как усложнение в задаче нужно было восстановить ответ. В этих случаях, на мой взгляд, проще всего написать рекурсивную реализацию динамики (хорошо протестировать её на работоспособность), затем скопировать всю динамику на восстановление ответа (для деталей выкладываю свой код). Конечно это можно делать и без копипасты, например, передавая в динамику булеву величину нужно ли восстанавливать ответ.
Асимптотическая сложность решения: O(n2).
Вопрос по D. Вот мой код в точности реализующий вышеописанный алгоритм 15019349 Почему у темя ТЛ 19?
Медленный ввод-вывод. Вот это 15020347 получает OK.
Скорее всего проблема в скорости ввода/вывода. Не используйте cin/cout (scanf/printf работают значительно быстрее). Мы только из-за этих проблем поднимали TL с двух до четырех секунд, но больше поднять мы не могли.
Медленный ввод-вывод. Такая версия твоего кода заходит: 15020362
Точнее проблема в вводе. Вывод скорее всего успевает.
Столкнулся с той же самоей проблемой. Как только поменял cin/cout на scanf/printf — сразу же управился в секунду, хотя раньше не хватало даже четырех.
Стоит опубликовать эту информацию на английском языке, так как многие участники не имеют доступ к этим комментариям. Я вообще сначала думал что проблема со временем возникает из-за использования вектора, а оказывается все намного проще.
Этот вопрос многократно обсуждался на Codeforces. Я понимаю, что трудно прочитать весь Codeforces, с этим просто нужно в какой-то момент столкнуться, либо нужно читать коды топовых чуваков и задумываться над тем, почему они не используют удобные cin/cout, а пишут старые сишные scanf/printf.
По-моему достаточно добавить строку ios_base::sync_with_stdio(0); cin начинает работать по скорости как scanf, а иногда и быстрее.
Да кстати задачи очень интересные и учебные!!! Спасиб за контест!!!
Can we get the editorial in english ? Please....
I'm working on it.
Thanks
Done.
It would be nice if we get the sample codes for all the problems ....
Not like there aren't hundreds of solutions to all the questions as it stands... just look at some other people's code, you'll gain a lot of new tricks you never knew about before!
For A, there's also a simple O(N) DP solution in which F[i] is true if we can represent i as A*p+B*q or false otherwise. It's easy to restore a possible sequence if F[n] is true :)
Also you can simply iterate from 0 to max_possible_B and check if ((n — i*q) mod p == 0). If found — its an answer. If not — impossible.
Hi there!
In trying on Problem E, I implemented the idea per the Editorial, to create and sort events, and linearly scan them. But I got TLE on input #19. Any ideas?
I'm not sure if it's appropriate to paste my code here. But if so, I'd love to share with you and receive any feedbacks!
You can post a link to you submission. When looking at your profile history, I see the submission history anyway.
Your I/O is too slow. There has been written a lot about
cout/cin
vs.scanf/printf
on Codeforces, just search.First, do not use
endl
after every line — it flushes the output buffers, therefore is slow.Second, add this code at start of
main()
:Then try again and it should be AC.
Totally lost in editorial of "The Union of k-Segment". what is the "balance" and what is "decrease the balance".
what is the deal with event time?in simple words please.
The algorithm being used is a Sweep line algorithm. We're sweeping the x-axis from left to right. It makes sense to call the openings and closings of the given segments 'events'. Since we want to sweep the x-axis from left to right, we're going to create a bunch of events, sort them by x-coordinate, then process them.
The balance is the number of segments that have been opened so far as I'm sweeping the x-axis. When this balance is increased to
k
, you're in a satisfied part of the x-axis. When the balance decreases fromk
tok-1
, you're on the boundary of a satisfied part of the x-axis.I am not able to understand Square Root of Permutation editorial can someone provide detailed expalnation for that ?? It will be really helpfull :)
Here are some hints: http://math.stackexchange.com/questions/266569/how-to-find-the-root-of-permutation
The answer still may be too advanced to understand if haven't studied the math of permutation groups. Basically, every permutation can be expressed in a cyclic notation. To do that, first write the permutation as multiplication of transpositions (a transposition is a cycles with two elements). For the example
q = [4, 5, 1, 2, 3]
, 1 maps to 4, 2 to 5 and so on, so we write it down:q = (1 4)(2 5)(3 1)(4 2)(5 3)
Now some transpositions can be merged. In fact in this example all of them can be merged, but that will not always be the case:
q = (1 4 2)(2 5)(3 1)(5 3) = (1 4 2 5)(3 1)(5 3) = (1 4 2 5 3)(3 1) = (1 4 2 5 3)
The resulting cycle of length 5 denotes the same original permutation
q
, just in a different way.Now if
q=(i1, i2, i3, i4, i5)
then inq^2
elementi2
moves one step away fromi1
:q^2=(i1, ..., i2, ...)
, elementi3
one step away fromi2
and so on (modulo the size of the permutation):q^2=(i1, i4, i2, i5, i3)
In the example,
q^2 = (1 4 2 5 3)^2 = (1 2 3 4 5)
. Written back in the original form, it is the permutationp = [2 3 4 5 1]
.The analysis so far works for cycles with odd length. For a cycle with even length
l
, for examplep = (i1, i2, i3, i4)
elementi_n-2
maps back toi1
and so on; the result in this case is two cycles with lengthl/2
:p = (i1 i3)(i2 i4)
To solve the exercise, you need to do the opposite: permute every odd-sized cycle back, and merge every pair of same-sized even cycles. (If there are more than one pair of cycles with size
2n
, then multiple solutions exist.) If there are even-sized cycles with no pair, then a solution does not exist.Finding the cycles in the given permutation requires some preprocessing, but it can be done in
O(n)
time.thank you.
It seems that while explaining how to find the square of a permutation, you have explained how to find the root of the permutation.
Link to editorial(tutorial) added under contest material on contest page is not working(redirecting to edit blog link).
D getting TLE for O(NlogN) in python.
Python isn't really a good choice for competitive programming. Some simple algorithms works there like 40 times slower than C#/Java/C++.
On top of than you should have very fast console i/o. It could be impossible to solve this task in Python at all.
You are right. I just wanted to know if anyone got AC for that problem in python.
Question to people who solved problem E in round what made you think of this problem as a graph problem? and what lead you to that observation i mean i've been to solve graph problems for a while and still i can't reach that graph mentality which enables me to realize the point of such a problem if anyone would kindly share their experience or a few pointers that would be great
Question to people who solved problem E in round what made you think of this problem as a graph problem? and what lead you to that observation i mean i've been to solve graph problems for a while and still i can't reach that graph mentality which enables me to realize the point of such a problem if anyone would kindly share their experience or a few pointers that would be great (p.s: sorry for double post but first time was by mistake in russian)
It is quite standart idea to consider a permutation graph. And in this problem some outputs for small cases helped me to get the right idea;)
Can you please provide some links to tutorials or problems , where this idea has been used .
I don't know about articles on English about it, you may take a look at Wikipedia though or try to find some other information in Google. There had been some problems on Codeforces with such idea but i could not find them now. One of the famous problems is to find the k-th power of the given permutation of size n. It can be solved with O(n log k) complexity using binary exponentiation but with idea of the permutation graph it can be done in O(n).
It seems to me that the solution for F is a bit incorrect. Especially, recalculating of z1. It is claimed that we need to move only in one direction (i.e. clockwise or counterclockwise). However, sometimes we need to move in one direction, then return to the initial point and continue moving in the direction, opposite to the initial direction. For example, test:
We need to do the following sequence of steps: +0, -1, +2 (or -1, +1, +1) firstly. And the suggested author's solution gives correct answer to this test. Can you please explain, what's going on?
I know it's been three years, but I also stumbled on this, so maybe it will help future upsolvers.
If you define $$$z1_i$$$ as the minimal cost of starting at position $$$i$$$ and visiting all positions with values greater than or equal to $$$a_i$$$, then indeed you have to consider a general case: move in one direction to some $$$j$$$, then move in other direction to some $$$k$$$:
In the picture above going only in one direction from $$$i$$$ will give too big cost $$$z1_i$$$. But note that cost $$$z1_j$$$ will be calculated correctly.
Now consider calculating $$$z2_x = \min_y(z1_y + d_{xy})$$$ for some position $$$x$$$ where $$$a_x$$$ is the biggest value smaller than $$$a_i$$$. If it's optimal to move from $$$x$$$ to $$$i$$$ (i.e. $$$y=i$$$ achieves minimum), then we make a move from $$$x$$$ to $$$i$$$ and then to $$$j$$$. Since all values $$$a_i$$$ will be visited on path from $$$j$$$ to $$$k$$$, we could have moved directly from $$$x$$$ to $$$j$$$. Thus $$$y=j$$$ also achieves minimum, and since $$$z1_j$$$ is correct, then $$$z2_x$$$ will also be correct.
To summarize: values $$$z1_i$$$ in author's solution are sometimes bigger than advertised, but it doesn't matter, since there is at least one correct value that achieves minimum.
Question about 612E: I didn't get what the editorial means with merge cycles in each pair. For example, the permutation
2 1 4 3
has two cycle of size 2 which are2->1->2
and4->3->4
. How should I merge this?I ran one correct solution for this input and I got
3 4 2 1
which means that the result of merge should be3->2->4->1->3
. But I didn't get the idea behind the merge process.See my answer to masterwayne
Can someone explain me why C problem 11-th test answer is 7? Input:
(([{>}{[{[)]]>>]
My program outputs 3 and I when I tried to do this manually I also found that only 3 changes are needed:
(([{>}{[{[)]]>>]
'<'([{>}'<'['<'[)]]>>]
Did I misunderstand the problem or the test is wrong?
Why in Problem D. The Union of k-Segments in first sample test with input:
we get output
and not
as far as I can see all the points of interval 0 5 belongs to at at least 2 segments therefore set of one segment (0 5) is the smallest?
Actually it's not. Here the problem says that all satisfied points (I presume that you are mistaking for satisfied INTEGER points) must be included. Indeed, 2 and 3 are satisfied points but 2.5 is not
you can solve problem A using dp in linear time 167881923
For the future solvers
Problem D
test#1 case ans is two segments because all the real numbers between 2 and 3 aren't satisfying the condition
test#2 case all the real numbers between 2 and 3 also satisfying the condition so only one interval is required
My appraoch
since real numbers check is required so our standard sweep line template wont work, we need to add some more checks, the way i did it quite easy to understand i think,
lets say our current interval is [ a , b ] and previous valid interval is [ c , d ] if these points are integer then can't have the information of the numbers in between two intervals so we need real numbers, but that will not be very intuitive when implementing.
so what i did is, multiplied each interval end point by 100,
and updated the map, mp[left]++ , mp[right+1]--;
now if two intervals differ less than 2 then they can be merged if not they will be seperated,
this above implementation is same as having real number of precision of 0.01, but we are doing it with integers only.
here is the my AC code implementation: