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

Автор Connector, 13 лет назад, По-русски

Задачи A(div2), B(div2)

В этих задачах требовалось реализовать ровно то, что описано в условии. В задаче B не рекомендовалось использовать BigInteger в Java из за скорости работы с ним.

Задача C(div2), A(div1)

В этой задаче буквы из строки s1 следовало набирать жадно: брать самую левую букву справа от последней использованной, если требуемой буквы не было справа от последней использованной, то следовало начать поиск с начала строки s1 и увеличить ответ на единицу. Однако реализация "в лоб" получала TL и имела асимптотику O(Ans * |s1|)

Это решение можно оптимизировать, например, следующим образом. Для каждой позиции в s1 предпосчитать позиции самых левых символов от текущего для всего алфавита. Это можно было реализовать идя справа налево в строке s1 храня позиции последнего вхождения символа каждого вида в строку. Такое решение имеет асимптотику O(|s1| * K + |s2|), где K --- размер алфавита.

Другая оптимизация подразумевала хранение 26-и сбалансированных деревьев или отсортированных списков (по одному для каждого символа) состоящих из позиций вхождения того или иного символа. С помощью них, используя lower_bound, можно было искать самый левый нужный нам символ справа от текущей позиции. Такое решение имеет асимптотику O(|s1| + |s2| * log(|s1|).

Задача D(div2), B(div1)


Авторское решение подразумевает следующее. Предпосчитаем все минимумы на отрезках вида [i, n]. Это можно выполнить за O(n) также идя справа налево. Обозначим минимум на отрезке [i, n] за Mini. Очевидно, что Mini <  = Mini + 1. Теперь для каждой позиции i с помощью бинарного поиска найдем такое число j > i, что Minj < ai и Minj + 1 >  = a{i}. Для такого числа j утверждается, что среди моржей с номером j и более нету моржей младше моржа i. Это очевидно так, как Minj принимает значение минимального возраста моржа на отрезке [j, n]. Если такого j не нашлось то следует вывести  - 1 иначе j - i - 1.

Задача E(div2), C(div1)


Будем считать количество лыжных баз включая базу из пустого подмножества ребер (при выводе просто отнимем единицу). Изначально количество лыжных баз равно 1. Если мы соединяем вершины которые были в одной компоненте связности, то результат умножим на два, в противном случае ничего делать не надо. Для того, чтобы быстро узнавать лежат ли две вершины в одной компоненте связности и быстро объединять компоненты можно было использовать DJS.

Теперь самый смак. Почему же это верно?
Для доказательства используем матрицу инцидентности I, строками будут являть ребра, столбцами --- вершины. Определим xor двух строк. Xor'ом двух строк a и b является строка c такая, что ci = ai xor bi. Заметим, что если xor нескольких строк равен строке содержащей только нули, то ребра соответствующие взятым строкам образуют лыжную базу. Действительно, степень смежности каждой вершины четна, а значит в каждой компоненте из взятых можно построить эйлеров цикл (Необходимые и достаточное условие существования эйлерова цикла: четность степени смежности каждой вершины и связность графа). Ответом будет являться 2(m - rank(I))

Почему это так? Если справа от каждой строки в матрице приписать индекс соответствующего ребра и искать ранг матрицы с помощью метода Гаусса и при xor'e строк выполнять xor наборов ребер записанных справа, то в итоге наборы ребер которые будут записаны справа от нулевых строк будут образовывать базис линейного пространства. В доказательство корректности этого я приведу алгоритм поиска ранга матрицы из которого это будет очевидно.

Найдем ранг матрицы, как обычно, используя метод Гаусса и пометим строки которые остались не нулевыми. Теперь вернемся к исходной матрице, но с запоминанием помеченных строк. Теперь будем искать так же ранг матрицы, но не помеченную строку приводить к нулевой будем только выполняя ее xor с помеченными строками.

Пример:
1 1 0 a*
0 1 1 b*
1 0 1 c
1 0 1 d

1 1 0 a*
0 1 1 b*
0 0 0 c + a +b
0 0 0 d + a +b

Так как наборы ребер записанные справа образуют базис, то ни один набор записанный справа от нулевой строки не должен получаться путем комбинации (xor'а) других наборов записанных справа от нулевых строк. Действительно это так потому, что справа от нулевой строки будет находиться ребро соответствующее ей изначально и ни в каком наборе записанном справа от нулевой строки оно не встретится т.к. мы выполняли xor только с помеченными строками.

Осталось заметить, что строка, соответствующая ребру, соединяющему вершины a и b, в матрице инцидентности является линейно зависимой, если до добавления ребра существует путь из a в b (мы можем проxorить ее со всеми строками соответствующими ребрам на пути из a в b).

Задача D(div1)
Выделим все циклы в подстановке вида:
1 2 3 4 5 ...
a1 a2 a3 a4 a5 ...
Например, в последовательности a = {2, 1, 4, 5, 3} есть 2 цикла длины 2 и 3 на позициях 1 2 и 3 4 5 соответственно. Если длина цикла больше 5, то взяв 5 последовательных элементов можно их переставить так, что 4 из них встанут на свои места. Так же можно взять 4 элемента и получить 3 элемента на своих местах. В общем виде: если мы берем p элементов в цикле длины больше p, то можно переставить их так, чтобы p - 1 встали на свои места. Если длина цикла равна p, то можно взять p элементов и поставить все из них на свои места. Поэтому для общность далее я буду говорить о длине цикла, как о его длине - 1 (теперь можно всегда говорить, что если взять p элементов, то p-1 встанут на свои места).
Не всегда все элементы выгодно брать в одном цикле, можно брать несколько в одном и несколько в другом. Таким образом можно получить разбиения чисел до 5 на их сумму: 5, 4, 3, 2, 2 + 3, 2 + 2. Можно взять, например, три элемента в первом цикле и два во втором, их длины уменьшатся на 2 и 1 соответственно.
Задача заключается в том, чтобы довести все длины циклов до нуля. Предположим в что в оптимальном решении нам следовало бы четыре раза уменьшать один и тот же цикл (a) на единицу. Будем считать, что выполнялись операции где берется ровно по 5 элементов и они не применялись к одним и тем же циклам, за исключением a. Такое условие является более строгим так как при пересечении операций в других циклах или при выборе меньшего количества элементов можно использовать менее продуктивные операции.
Схематично это можно представить в виде таблицы: строки --- это операции, столбцы --- циклы, а в клетках записаны значения на которые уменьшается тот или иной цикл.
a    b   c    d    e
1    2
1        2
1              2
1                   2 
Заменим операции на следующие:
a    b    c    d    e
4
      2   1
           1    2
                       2
Количество операций не изменилось, но теперь стало видно, что если существует оптимальное решение, где встречается четырежды уменьшение цикла на единицу, то существует оптимальное решение где не встречается четырежды уменьшение цикла на единицу. Приведем еще несколько замен подобной выше:
a    b    c
2    1
2          1
Заменим на:
a    b    c
4
      1    1

и

a    b    c    d
2    1
1         2
1               2
Заменим на:
a    b    c    d
4
      1   2
                 2
Из этих замен вытекает то, что существует оптимальное решение в котором один и тот же цикл не уменьшался на 1 + 1 + 1 + 1, 2 + 2, 1 + 1 + 2. Отсюда следует, что каждый цикл следует уменьшать жадно на 4 элемента пока его размер  >  = 4. Таким же методом докажем, что если остались после жадного набора циклы длины 3, то их следует уменьшать сразу на 3.

a    b    c  
2    1
1          2
Заменим на:
a    b    c    d
3
      1    2

a    b    c    d
1    2
1         2
1               2
Заменим на:
a    b    c    d
3
      2   1
           1    2

Теперь остались только циклы длины 2 и 1. Будем перебирать количество операций вида {2, 2} -  > {0, 1} (один цикл длины два уменьшается на два, другой цикл длины два уменьшается на единицу), которые следует выполнить. Пусть мы зафиксировали некоторое количество таких операций. Теперь выполним максимальное количество операций вида {2, 1} -  > {0, 0}. После их выполнения у нас либо не останется циклов положительной длины, либо останутся циклы только длины 1, либо останутся циклы только длины 2. Во втором случае следует выполнять операции вида {1, 1} -  > {0, 0} и если останется один цикл, то следует применить операцию {1} -  > {0}. В третьем случае следует выполнять операции {2} -  > {0}. Перебирая количество операций {2, 2} -  > {0, 1} и выполняя описанные выше действия мы найдем оптимальное решение. Разбивать цикл не несколько циклов меньшего размера не имеет смысла. Стресс тест показал, что объединение циклов тоже не ведет к улучшению.

Задача E(div1)


Формально нам задан массив значение в ячейке которого описывается функцией зависящей от времени T vali = ai + bi * T (в геометрическом смысле это уравнения прямых). Разобьем массив на блоки величины d ~ sqrt(n): [0;d), [d, d * 2), [d * 2, d * 3), ..., [d * k, n). Теперь предпросчитаем моменты времени, когда меняется лидер на блоке. Так как у нас есть уравнения прямых, то можно воспользоваться алгоритмом пересечения полуплоскостей образованных разрезанием плоскости уравнениями прямых из обрабатываемого блока. На оси Oy отмечаются высоты, на оси Ox --- время. Нас будет интересовать только координаты x точек пересечения полуплоскостей и номера прямых которые пересекаются в этой точке. Будем считать, что для каждого блока мы нашли моменты времени, когда меняется лидер и номер лидирующего после этого момента. Для каждого блока это займет O(d * log(d)) времени. так как блоков (k) у нас примерно n / d ~ n / sqrt(n) ~ sqrt(n), то весь препроцессинг займет O(n * log(n)) времени.

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

Всего удалений моментов времени смены лидера будет не больше O(n), а не считая удаление моментов времени смены лидера, каждый запрос обрабатывается за O(sqrt(n)). Итоговая асимптотика равна O(n * log(n) + m * sqrt(n))

Для решения этой задачи можно было воспользоваться деревом отрезков и получить асимптотику O(n * log(n)), но использование O(n * log(n)) памяти.

Разбор задач Codeforces Beta Round 75 (Div. 1 Only)
Разбор задач Codeforces Beta Round 75 (Div. 2 Only)
  • Проголосовать: нравится
  • +52
  • Проголосовать: не нравится

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

А когда появится разбор D(div2) она же  B(div1) ?

UPD: а вот и он :)
13 лет назад, # |
Rev. 4   Проголосовать: нравится +15 Проголосовать: не нравится
Насчет

Задача E(div2), C(div1)

Речь идет о количестве элементов в пространстве циклических элементов (наборы ребер которые можно разбить на циклы, подпространство в Z2m), будем считать ответ вместе с пустым элементом.
 Пусть компонента связности одна , возьмем остовное дерево. Взяв любое ребро не из дерева можно достроить его до цикла с помощью ребер из дерева. Более того, любой набор ребер не из дерева достраивается до циклического элемента, это легко доказать. Таким образом, все ребра не из дерева являются базисом данного пространства, а значит всего циклических элементов 2(m - n + 1). В общем случае каждое ребро не объединяющее две компоненты удваивает ответ.
  • 13 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится
    Да, ещё добавка. Если брать такую матрицу как описана в условии, то гаусс на ней эквивалентен dfs, в качестве базиса можно брать набор остовных деревьев компонент связности.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Так всё намного более понятно спасибо.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Допустим, мы взяли набор ребер не из дерева и достроили его до циклического элемента. Почему нельзя его построить с помощью другого набора?
13 лет назад, # |
Rev. 2   Проголосовать: нравится +1 Проголосовать: не нравится

Расскажите если не сложно почему вот такое решение не работает к Задаче D(div2), B(div1)
Сортируем моржей по неубыванию возраста, сохраняя в отдельном массиве их бывшие позиции. Далее идём по массиву с начала до конца, сохраняя минимальную бывшую позицию и сравнивая её с бывшей позицией текущего моржа.
 Наверное криво объясняю, может вам код поможет 505447

UDP: 
Решение проходит, одной строчки не хватало.
  • 13 лет назад, # ^ |
      Проголосовать: нравится +5 Проголосовать: не нравится
    Отлично работает решение... Только моржей одинакового возраста еще и по позиции надо сортировать.
    • 13 лет назад, # ^ |
        Проголосовать: нравится +8 Проголосовать: не нравится
      о... Дополнительно по позиции я не догадался сортить. Я делал тупую сортировку, ответ пересчитывал для отрезков моржей с одинаковым возрастом, а позицию крайнего моржа для каждого отрезка обновлял после нахождения ответа для этого отрезка.
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Я нашёл у себя ошибку, одну строчку недописал.
      По позиции можно не сортировать, это никак не влияет(в моём решении).
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Наверно у меня кривой стиль мышления, но задачу B (div. 2) я решал дольше, чем C и D вместе взятые. Я побоялся и написал решение за линию. Или так и задумывалось?
  • 13 лет назад, # ^ |
      Проголосовать: нравится +4 Проголосовать: не нравится
    А как не за линию?
    • 13 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится
      Ну я видел у многих в коде (который получил "Полное решение") вложенный цикл при добавлении 1.
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        А почему вы решили, что это не за линию? 
        • 13 лет назад, # ^ |
          Rev. 4   Проголосовать: нравится -10 Проголосовать: не нравится

          Потому что словосочетание "вложенный цикл" скорее всего означает "за квадрат"?

          UPD Я не прав. Поставьте пожалуйста минус если хотите чтобы в следующий раз я думал прежде чем оставлять комментарий.
          • 13 лет назад, # ^ |
              Проголосовать: нравится +3 Проголосовать: не нравится
            Алгоритм Укконена - несколько вложенных циклов с рекурсией работает за линию))
            • 13 лет назад, # ^ |
                Проголосовать: нравится +14 Проголосовать: не нравится
              Словосочетание "вложенный цикл" означает "за квадрат", за исключением тех случаев, когда оно означает что-нибудь другое)
          • 13 лет назад, # ^ |
              Проголосовать: нравится +4 Проголосовать: не нравится
            Но это никак не одно и то же. В моем решении на ту задачу два вложенных цикла двигают один указатель и работает оно, разумеется, за линию. 
      • 13 лет назад, # ^ |
          Проголосовать: нравится 0 Проголосовать: не нравится
        Может я конечно чего-то не понимаю, но это же вроде квадрат (решение моего знакомого)?
        • 13 лет назад, # ^ |
          Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

          Так мы всё равно по каждой цифре больше двух раз не проходим, один раз когда нули проставляем, другой раз когда "кушаем"(то есть сдвигаем вправо). Посему линия.
          UPD: на самом деле не больше трёх раз. Ещё 1 раз может быть когда меняем 0 на 1
13 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

Thanks , Good Editorial , sorry but where is the Div1 - Problem D editorial ?
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
E (div 1)
А где можно прочитать об алгоритме пересечения полуплоскостей образованных разрезанием плоскости уравнениями прямых?
Сам сдал её sqrt декомпозиция + стеки. Может я его и написал...
  • 13 лет назад, # ^ |
      Проголосовать: нравится +1 Проголосовать: не нравится

    Тут пересечение полуплоскойстей для частного случая: у нас все вектора нормали во 2 четверти. Авторское тоже строит пересечение с помощью стэков.

    А алгоритм пересения полуплоскойстей в общем виде я тоже не отказался бы узнать =)

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

Задача B (div. 1) - можно было решать проще. Просто для каждого элемента запомним его номер и отсортируем. Потом будем идти, начиная с самых маленьких значений, и поддерживать позицию самого удаленного элемента, просмотренного до сих пор. Если она больше позиции текущего элемента - кидаем в ответ разницу между ними, если меньше - кидаем -1.
  • 13 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится
    Добавлю, что если правильно отсортировать, задача превращается в жуткий баян. Если сортировку по первому индексу(возраст) делать по возрастанию, а вторую(позиция)-по убыванию. Тогда нам нужно просто запоминать минимальную позицию, не делая больше никаких проверок.
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Problem E(div1)
 
For each block it takes O(d * log(d)) time.
Why O(d * log(d))?
13 лет назад, # |
  Проголосовать: нравится +4 Проголосовать: не нравится
Thanks for your analysis
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
I don't understand how we intersect that segments and how we can find the maximum for a given time T. I neither know what half planes intersection are. Can someone explain it to me?
Thank you!
13 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится
Почему у меня на таком коде в задаче В (div. 2) получается time-limit?
int c=-1;
    string str;
    cin>>str;
    while (str.length()>1)
    {
        while (str[str.length()-1]=='0')
            {
            str.erase(str.length()-1,1);
            ++c;
            }

     ++c;
    int l=str.length();
    if (l>1)
    {

    if (count(str.begin(),str.end(),'1')==l)
        {
            string substr(l,'0'),substr2(1,'1');
            str=substr2+substr;
        }
    else
        {
            int x=str.find_last_of('0');
            str[x]='1';
            str[l-1]='0';
        }
    }
    }
    if (c<0) ++c;
    cout<<c;
  • 13 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    Вы используете очень много функций, которые работают не за O(1).

    str.find_last_of('0');

    count(str.begin(),str.end(),'1')

    str=substr2+substr;

    Всё это работает за линию. 

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


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

Hello, I think the editorial might have a small problem. Or maybe it's just because my understanding is wrong?

For problem D(div 1)

the editorial mentions:

In the third case we should to do operations like {2} -  > {0}. Using such way we can find the optimal set of operations. We shouldn't divide cycle into a parts because it makes the number of operation bigger or the same. Stress test shows the uniting cycles will not improve the answer.

However, in test case #9 9 2 3 1 5 6 4 8 9 7 The algorithm in the editorial to eliminate {2} -> {0} fails.

In my opinion, {2,2,2} -> {0,0,0} in 2 steps. then {2} -> {0}. It's better.

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

Can somebody please explain Egor's solution for the Div1 B problem? In particular what does the order function do exactly. I have seen Egor use it in other contexts, and I have not been able to comprehend it. Any help would be appreciated, I have spent an hour trying to understand what this code does, and have basically made no progress. Link to Egor's submission: 499718

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

    I know that this comment was made 13 months ago :) Decided to write an answer since maybe there will be someone confused who might find my explanation helfpful.

    The key in this approach lies in understanding what does "order" do. It just orders indexes according to increasing values in the array. In 1st step we look at the index with the smallest element, in the 2nd step at the one with the 2nd smallest and so on. Answer for current index is (index farthest away from done so far) — (current position), because all already considered have values smaller than the current one. Let's look at the first test:

    6

    10 8 5 3 50 45

    "order" function allows to consider indexes in the following order:

    4 3 2 1 6 5

    We start with index 4 (arr[4] = 3, 3 is the smallest element in the array), 4 is better than the current max (-1), so 4 is now index farthest to the right from the ones already considered. And since it's max, the answer for index 4 is -1. Next we get to index 3 (arr[3] = 5, 5 is 2nd smalles element in the array). It's index is "worse" than the max so it means that the result for 3 will be max — 3 + 1. The same goes for indexes 2, 1. After that, we get to index 6 (arr[6] = 45, 45 is 5th smallest element). 6 is farthest to the right from the ones already considered, so our max is now 6. Result[6] = -1. Last step, index 5, not better than the max, result[5] = max — i + 1 = 6 — 5 + 1 = 0.

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

Problem E(div2), C(div1)
Very Nice problem and solution. :)

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

can someone please help me in the editorial for div2-E problem

In the end the subsets of edges written from the right of the zero rows will form the basis of the linear space

what is the linear space we are talking about? the third paragraph is confusing for me

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

Is there a solution for DIV 2 E / DIV 1 C which doesn't require knowledge of matrix?

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

    Consider a forest $$$T$$$ where we only add edges that don't form cycles. For each edge $$$e$$$ of $$$G \setminus T$$$ there exists a unique cycle $$$c(e)$$$ in $$$(G \setminus T) \cup {e}$$$. Consider a subset $$$E \subset (G \setminus T)$$$ of edges and form a corresponding ski base as $$$B(E) = \oplus_{e \in E} c(e)$$$.

    An inverse mapping is also well-defined: say there exists a cycle $$$C'$$$ that contains a subset of edges $$$E$$$ (and only them) but is not $$$C = \oplus_{e \in E} c(e)$$$. Then $$$C' \oplus C$$$ is a ski base that only contains edges from $$$T$$$, a contradiction with $$$T$$$ being an acyclic graph.

    Hence the number of (nonempty) ski bases is equal to the number of (nonempty) subsets of $$$G \setminus T$$$.

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

I have a |s2|*log(|s1|) solution for div2 C We can map the index of occurence of a letter to it's set(c++ stl set). let the map be indices[26]. We will maintain a current pointer(cp) which points to the index of our current location in s1. initially it is set to -1. Then as we iterate over s2: We will find the indices[s2[i]].upperbound(cp). if it is not null we'll set cp as the indices[s2[i]].upperbound(cp). otherwise: 1.) we will need a new headline and hence we will increment the count. 2.) we will set cp as-1; 3.) find upperbound again . if null then the the character is not present in whole of the headline. print -1 and terminate program. otherwise set cp as the upperbound.