Блог пользователя Edvard

Автор Edvard, история, 9 лет назад, По-русски

612A - The Text Splitting

Переберём количество строк длины 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).

612F - Simba on the Circle

Авторское решение по этой задаче основано на динамическом программировании. На мой взгляд никакие жадные идеи в этой задаче не работают. Для решения задачи будем считать две динамики 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).

Code

Разбор задач Educational Codeforces Round 4
  • Проголосовать: нравится
  • +23
  • Проголосовать: не нравится

»
9 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится

Вопрос по D. Вот мой код в точности реализующий вышеописанный алгоритм 15019349 Почему у темя ТЛ 19?

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Медленный ввод-вывод. Вот это 15020347 получает OK.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится

    Скорее всего проблема в скорости ввода/вывода. Не используйте cin/cout (scanf/printf работают значительно быстрее). Мы только из-за этих проблем поднимали TL с двух до четырех секунд, но больше поднять мы не могли.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Медленный ввод-вывод. Такая версия твоего кода заходит: 15020362

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Точнее проблема в вводе. Вывод скорее всего успевает.

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Столкнулся с той же самоей проблемой. Как только поменял cin/cout на scanf/printf — сразу же управился в секунду, хотя раньше не хватало даже четырех.

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

      • »
        »
        »
        »
        9 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится

        Этот вопрос многократно обсуждался на Codeforces. Я понимаю, что трудно прочитать весь Codeforces, с этим просто нужно в какой-то момент столкнуться, либо нужно читать коды топовых чуваков и задумываться над тем, почему они не используют удобные cin/cout, а пишут старые сишные scanf/printf.

        • »
          »
          »
          »
          »
          9 лет назад, # ^ |
            Проголосовать: нравится 0 Проголосовать: не нравится

          По-моему достаточно добавить строку ios_base::sync_with_stdio(0); cin начинает работать по скорости как scanf, а иногда и быстрее.

»
9 лет назад, # |
  Проголосовать: нравится +8 Проголосовать: не нравится

Да кстати задачи очень интересные и учебные!!! Спасиб за контест!!!

»
9 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится

Can we get the editorial in english ? Please....

»
9 лет назад, # |
  Проголосовать: нравится +3 Проголосовать: не нравится

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 :)

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +17 Проголосовать: не нравится

    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.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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!

  • »
    »
    9 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

    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():

        ios::sync_with_stdio(false);
        cin.tie(0); cout.tie(0);
    

    Then try again and it should be AC.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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.

  • »
    »
    9 лет назад, # ^ |
    Rev. 3   Проголосовать: нравится +1 Проголосовать: не нравится

    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 from k to k-1, you're on the boundary of a satisfied part of the x-axis.

»
9 лет назад, # |
  Проголосовать: нравится +9 Проголосовать: не нравится

I am not able to understand Square Root of Permutation editorial can someone provide detailed expalnation for that ?? It will be really helpfull :)

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    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 in q^2 element i2 moves one step away from i1: q^2=(i1, ..., i2, ...), element i3 one step away from i2 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 permutation p = [2 3 4 5 1].

    The analysis so far works for cycles with odd length. For a cycle with even length l, for example p = (i1, i2, i3, i4) element i_n-2 maps back to i1 and so on; the result in this case is two cycles with length l/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.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Link to editorial(tutorial) added under contest material on contest page is not working(redirecting to edit blog link).

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

D getting TLE for O(NlogN) in python.

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +6 Проголосовать: не нравится

    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.

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      You are right. I just wanted to know if anyone got AC for that problem in python.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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

»
9 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

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)

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +7 Проголосовать: не нравится

    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;)

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится +5 Проголосовать: не нравится

      Can you please provide some links to tutorials or problems , where this idea has been used .

      • »
        »
        »
        »
        9 лет назад, # ^ |
        Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится

        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).

»
9 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

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:

10 5
1 1 1 0 0 0 1 1 1 1

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?

  • »
    »
    5 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    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$$$:

            j <------ i
              -------------> k
    
    --------X---X-X---X--X---X---------------
    

    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.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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 are 2->1->2 and 4->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 be 3->2->4->1->3. But I didn't get the idea behind the merge process.

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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?

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Why in Problem D. The Union of k-Segments in first sample test with input:

3 2
0 5
-3 2
3 8

we get output

2
0 2
3 5

and not

1
0 5

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?

  • »
    »
    6 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    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

»
2 года назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

you can solve problem A using dp in linear time 167881923

»
8 месяцев назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

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:

my c++ code