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

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

205A - Маленький Слоник и Роздол

Это была самая простая задача из набора. Нужно просто отсортировать все расстояния (при этом поддерживая индексы) и, если первые два расстояния равны, вывести "Still Rozdil", иначе вывести индекс первого элемента.

Сложность решения O(NlogN).

205B - Маленький Слоник и сортировка

В этой задачи нужно заметить тот факт (который несложно доказать, но он понятен даже интуитивно), что, так как массив нужно сделать неубывающим, если делать какую-то операцию, то r (правая граница) должна быть равна n. Действительно, подняв правую часть массива мы точно не ухудшим результат. После этого нужно идти слева направо и жадно делать необходимое количество операций на каждом шагу.

Сложность решения O(N).

205C - Маленький Слоник и промежуток

Естественно, для того что-бы решить задачу нужно написать функцию F(x) которая будет решать задачу на промежутке 0..x, тогда ответом будет F(r) - F(l - 1).

Опишем реализацию функции F(x). Если x < 10, результатом будем сам x. Пусть len — длина числа x, а x' — число x без первой и последней цифр, а xii-я цифра числа x (от 0 слева направо). Переберем первую цифру d (она и будет последней) и длину того что внутри (пусть это будет i). Тогда если i < len - 2 или (i = len - 2 и d < x0), к ответу нужно добавить 10i. Иначе, если i = len - 2 и d = x0 то к ответу нужно добавить x', а если еще и i = len - 2, d = x0 и xlen - 1 ≥ d то нужно добавить еще 1 к ответу.

Также эту задачу можно было решить используя ДП.

205D - Маленький Слоник и карточки

Эту задачу можно удобно решить используя структуру map, но можно и обойтись без нее (используя сортировку и бинарный поиск). Давайте переберем цвет-кандидат который и приведет к веселости набора, для каждого цвета узнаем минимальное количество переворачиваний (если возможно вообще) и выберем минимум. Если никакой цвет не подходит, ответ "-1". Для того чтобы найти минимальное количество переворачиваний нам нужно узнать два числа — количество карточек которые изначально лежат текущим цветом вверх, а также количество карточек у которых сзади есть текущий цвет (при этом сверху какой-то другой). Пусть это числа a и b. соответственно. Пусть m = (n + 1) / 2 — минимальное количество одинаковых карточек необходимых для того, что-бы сделать набор веселым. Тогда текущий цвет может сделать набор веселым только если a + b ≥ m. Если a ≥ m, то ничего переворачивать не надо, то есть ответ 0, иначе ответ равен m - a.

205E - Маленький Слоник и Фурик и Рубик

Задача на математическое ожидание. Здесь важно учесть факт линейности математического ожидания, иными словами, ответ для какой-то пары строк это сумма количеств совпадений по каждому символам алфавита. Поэтому давайте для каждого символа первой строки найдем вероятность того, что он войдет в ответ. Тогда общим ответом будет сумма этих вероятностей.

Пусть у нас текущий символ в первой строки с номером i (всюду 1-нумерация). Сначала решим задачу за O(N2). Переберем все позиции j левее i (или равные i) такие что Bj = Ai. Тогда для какой-то позиции нужно найти количество возможных пар строк таких, что в них именно эти два символы Ai и Bj совпали. Это количество будет равно j(n - i + 1) (j возможных символов слева и (n - i + 1) справа, поэтому общее количество это их произведение). Это будет O(N2). Так как все это — сумма, то ответ будет равен Si(n - i + 1), где Si — сумма всех позиций j таких, что Bj = Ai. Массив S можно несложно посчитать за линейное время. Аналогичным образом нужно обработать все индексы что правее i.

После того как количество пар подстрок в которых i-й символ первой строки имеет совпадение найдено (пусть это count), к ответу нужно добавить count / total, где total — полное количество возможных исходов, его можно найти циклом или несложной формулой.

Сложность решения O(N).

204D - Маленький Слоник и ретро строки

Для начала нам нужно решить следующую подзадачу: для каждого префикса найти количество его заполнений таких, что он не содержит подстроки длиной k состоящую только из букв B. Пусть это будет F(x), где x это номер последнего символа префикса. Давайте присвоим F(x) = F(x - 1) * cnt, где cnt = 2, если Sx = 'X', 1 иначе. После такого присвоения в результат могли быть включены некоторые способы такие, что блок из k есть в конце префикса (они могли быть включены только если в подстроке Sx - k + 1..x нет букв W, а символ Sx - k не есть B), а это плохо. Поэтому (если такое могло произойти) нужно от F(x) отнять F(x - k - 1), это уберет все плохие варианты.

Аналогичное ДП нужно посчитать для для суффиксов (или, иначе говоря, для реверсовной строки S), только здесь нужно избегать блоков из W.

Теперь подумаем как организовать все что-бы не появилось повторов. Давайте переберем позицию, в которой будет заканчиваться первый слева блок из k подряд идущих букв B. При этом будем перебирать эту позицию справа налево. Используя ранее подсчитано ДП мы можем найти количество вариантов заполнить все буквы левее так, что-бы там не образовался блок. Если писать решение за O(N2), то мы можем перебрать позицию, в которой будет начинаться первый справа блок из k букв W, аналогичным образом найти количество способов заполнить все правее что-бы там не образовался блок, а символы между левым и правым блоками мы, очевидно, можем заполнять как-угодно. Но, так как мы идем справа налево, мы можем по ходу поддерживать сумму этих количеств. Это обеспечит нам линейность решения.

204E - Маленький Слоник и строки

Для решения данной задачи воспользуемся свойствами суффиксного массива. Болле подробно о суффиксном массиве можно почитать здесь:

http://e-maxx.ru/algo/suffix_array

Для начала нужно конкатенировать все строки в одну, при этом разделяя их какими-то символами которые не встречаются в строках. Например, три строки abc, a, ab можно склеить в одну следующего вида: abc#a@ab. Теперь нам нужно построить суффиксный массив по новой строке, это позволит нам отсортировать все циклические сдвиги строки. При этом первый символ каждого циклического сдвига это либо вспомогательный символ, либо символ какой-то входной строки.

Заметим теперь что для того что-бы найти результат нам нужно для каждого циклического сдвига, начало которого принадлежит какой-то входной строке, найти максимальную длину его префикса такую, что этот префикс является подстрокой как минимум k входных строк. Это число можно искать бинарным поиском, но для этого нужно какую-то функцию которая бы отвечала на вопрос: а сколько есть различных входных строк которые содержат префикс длины len циклического сдвига номер x (Пусть это функция F(x, len)).

Как же сделать функцию F(x, len)? Рассмотрим все циклические сдвиги, префикс длины len которых ровен префиксу длины len x-го сдвига. Заметим что, так как все сдвиги отсортированы лексикографически, набор таких сдвигов будет представлен каким-то промежутком [l;r] (1 ≤ l ≤ x ≤ r). Как же найти этот промежуток? Для каждой пары соседних сдвигов можно найти их наибольший общий префикс. Тогда l, например, можно найти используя RMQ — для этого нужно найти самую правую пару соседних сдвигов (левее x) таких, что их наибольший общий префикс меньше len. Аналогично можно найти r. После этого у нас есть промежуток [l;r] и нужно найти количество различных строк которые соответствуют этим сдвигам (иными словами, найти количество различных чисел в подмассиве). Но, заметим, что самое количество различных нас не интересует, а интересует только не меньше ли оно за k или нет. Тогда пусть L[i] равно максимальному j (j ≤ i) такому, что количество различных чисел в помассиве [j;i] ровно k. Тогда если L[r] ≥ l то, логично, что и в промежутке [l;r] также будет не меньше k различных чисел.

Осталось заполнить массив L. Это довольно просто сделать используя структуру set (можно также использовать RMQ). Будем идти слева направо и в сете поддерживать индексы самых правых k различных чисел. Тогда если поступает какое-то число, то (если оно встречалось раньше) его прежнее вхождение нужно удалить из сета (если оно еще осталось) и вставить текущее. При этом если размер сета превышает k нужно извлекать минимальный элемент. Тогда если в какой-то позиции i размер сета есть k (после описанных выше изменений), это означает, что L[i] ровно минимальному элементу сета.

Так как мы O(N) раз используем бинарный поиск, а функция F(x, len) работает за O(logN), финальная асимптотика решения равна O(Nlog2N).

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

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

Задача 205С. У тех, кто кодит на Си преимущество. У них 10^18 в long long влазит. А тем, кто кодит на Паскале или на Делфи приходиться писать длинную арифметику. Вывод : переходите на Си.

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

в задаче А (Div. 2) сложность, все-таки, O(N). Накой там сортировка?

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

    Чтобы написать за минуту, а не за полторы)

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

      Это какую же сортировку писать быстрее, чем два прохода по массиву?

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

        std::sort

        PS: Зачем два прохода по массиву. если достаточно одного?:)

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

          Он на паскале пишет, там встроенного сорта нету, нужно самому писать, ну либо копировать из папки в паскале...

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

            Так точно, капитан.

            Мыши давились и кололись, но продолжали жрать кактус.

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

        Arrays.sort(array); ?

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

          Не у всех есть возможность.

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

            Вам запрещают пользоваться другими языками? :(

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

              Нет, просто не все знают несколько языков..

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

                Если говорить о возможности, то возможность есть у всех. А вот желания изучить уже может не хватать.

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

                  Даже если есть желание выучить, на родном языке писать все равно лучше чем на другом, ИМХО.

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

                  Я понимаю, как натуральный язык может быть родным, но как таким может быть язык программирования?!

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

          чтобы в один прекрасный момент пасть жертвой антиквиксорт теста (: Хотя, можно написать собственную рандомизированную версию квиксорта, и всегда ее использовать. BTW, огромное спасибо за CHelper. Замечательный плагин

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

            Collections.shuffle(Arrays.asList(array));

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

              Или, чтобы не было многократного снижения производительности:

              void randomShuffle(int[] arr) {
                  Random rnd = new Random();
                  for (int i = arr.length() - 1; i >= 0; i--) {
                      int pos = rnd.nextInt(i + 1);
                      int temp = arr[pos];
                      arr[pos] = arr[i];
                      arr[i] = temp;
                  }
              }
              
              • »
                »
                »
                »
                »
                »
                »
                »
                12 лет назад, # ^ |
                  Проголосовать: нравится +3 Проголосовать: не нравится

                Начиналось, напомню, все с того, что не хотим писать проход по массиву

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

                  А зачем это писать? :) Можно юзать тот же самый CHelper, ну или просто в сжатом виде вбить в шаблон.

                  P.S. Я сам все-таки пишу не пишу, т.к. давно не попадались задачи, где нужно тупо отсортировать массив скаляров.

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

            Заводите массив Integer'ов, они сортятся mergesort'ом

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

            Я вот как коммент написал через секунду понял, что кто-нибудь обязательно это напишет :)

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

204E можно решать за O(n) — построим суффиксное дерево склеенной строки, посчитаем для каждой вершины в оффлайне количество различных разделителей, достижимых из нее, после этого ответ считается линейным проходом по дереву

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

    Задача E(div 2). Если поделить count на 2, то получится количество одинаковых подстрок двух строк. Прав ли я?

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

      Владислав писал про E(div1).

      А так нет, не правы. count — это всего лишь суммарное количество совпадений символов по всем парам подстрок одинаковой длины.

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

In "250A Little Elephant and Rozdil", It's no need to sort the distance.Just find ont the min_element and then check if it is unique, and the complexity is O(N) After all, it's such an easy problem that it is very easy solve. The O(N lg N) algorithm will not waste too much time, too.

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

    Yep, I agree. I did the O(N) solution but in retrospect the O(Nlog(N)) solution would have been much quicker to code. (Not that the O(N) solution took that long).

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

I am a beginner. Can anyone explain in a greater detail the problem "205C — Little Elephant and Interval".? While solving the problem during the contest, I worked it out that between 10^i and 10^(i+1), there are 9*10^(i+1-2) desired numbers. But, I could not translate it into solving it for any l<r. It would be a great help if you can explain both F(r)-F(l-1) and DP approach to solve this problem.

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

    It's not easy to code but a little difficult to understand.And please be patient to my poor English, thanks.
    As this issue said " F(x) which solves the problem for the interval 0..x" and the problem is how to cauculate F(x)
    let x = k * x1 + x2, x1 = 10 ^ n, ~/A means any number 1...9
    For example , x = 3534 and x1 = 1000 x2 = 534
    A~A, AA, A are allowed(as you know) (t1)
    and 1~~1, 2~~2 are allowed too (t2)
    At last, to the most difficult part, 3003 ... 3533 are allowed so (3534 — 3003) / 10 + 1 is the answer of the last part( 00...53 ) (t3)

    Sum (t1), (t2), (t3), and you will get the answer.
    I think my method is the same to the author, but it seems that we're describing it in different ways.

    Thanks for your patience to my English(I seemed to say it twice)

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

Can you please explain the DP solution of 205C — Little Elephant and Interval

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

    To answer F(x), in my DP the state is D[i][j][k], 0 <= i <= 9, 1 <= j <= digits of max number, 0 <= k <= 1, is the total amount of this numbers which I can build, remaining j digits to fill and with the first non-zero digit i. The variable k tells if the numbers I have chosen are the same in x, for example if x = 3553 and I have chosen 30-- then k = 0 and the third number can be [0,9] but if I have chosen 35-- then k = 1 and I can only choose [0,5]. Then F(x) = D[0][digits of x][1].

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

      I couldn't understand properly..it would be very nice of you ...if you could elaborate a bit

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

        The base cases are when j = 1, i.e i only have to fill one digit, in case i = 0 and k = 1 it means all the digits I have filled are 0 and I have to build a number with only a digit, in that case the answer is the last digit of x, there are to more base cases, when i != 0 and k is 0 or 1, in the first case D[i][1][0] = (i <= last digit of x), and the second D[i][1][1] = 1. The k = 0indicates that no matter what digit I choose now the number will be lower than x, and if k = 1 I can only use digits which are lower to the last digit of x.

        In the recursive case, I have to iterate through all possible digits I can use, in case k = 0 I can use whichever and otherwise I cant.

        Here is my code:

        ll D[10][20][2];
        string w;
        
        long long d(int i, int j, int k) {
            if (D[i][j][k] != -1) return D[i][j][k];
            if (j == 1) {
                if (i == 0 and k == 0) return 9;
                if (i == 0 and k == 1) return w[w.size() - 1] - '0';
                else if (k == 1) return i <= w[w.size() - 1] - '0';
                else return 1;
            }
            long long cont = 0;
            for (int e = 0; e < ((k == 0)?10:w[w.size() - j] - '0' + 1); ++e)
              cont += d((i == 0)?e:i, j-1, (k == 0)?0:e == w[w.size() - j] - '0');
            return D[i][j][k] = cont;
        }
        
        long long F(long long x) {
            memset(D,-1,sizeof(D));
            stringstream l; l << x;
            l >> w;
            return d(0,w.size(),1);    
        }
        
    • »
      »
      »
      4 года назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Basically 'k' is a restriction on the current digit right? if k = 0, then we can fill the current digit from 0 to 9 if k = 1, then we can fill the current digit from 0 to digit[digit.length() — j] where digit is an array containing the individual digits of "R"

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

On problem 204E — LE Strings.

I understand the procedure used to fill L. But since L depends on K, don't we need to calculate it each time? That would take O(total_size) time in each binary search. If you precompute it we must do it for each value of K up to max_length. Precomputation takes O(total_size*max_length) which is inefficient. Another idea might be thinking of L as a function and only filling L[r], but that would take O(total_size) as well.

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

Can someone explain the logic of probelm Little Elephant and Interval m not gettin it ??

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

My Dp solution for "C. Little Elephant and Interval" is similar to idea in this topic http://stackoverflow.com/questions/22394257/how-to-count-find-integers-between-large-a-and-b-with-a-certain-property

My code here : http://codeforces.com/contest/204/submission/6435651 But i get WA on Test 18, i test several times on my PC or some online IDE, the output should be 100000000000000008, but the judge output isn't it . Someone can help me determine the bug in my code ? Thanks in advance :).

P/s : I have found the bug, array dp must be dp[21][21][21] instead of dp[20][20][20] @@.

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

actually there is a O(NlogN) solution for 204E — Little Elephant and Strings.

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

If someone interested in DP solution for Div2 C, here it is: https://codeforces.com/contest/204/submission/86109648.

We need to calculate dp[len][first_dig][last_dig] — count of numbers length of len with first digit = first_dig, last digit = last_dig. After that we can calculate get(R) — cnt of numbers with first digit equal to last digit from 1..R. Be careful then num.size() == R.size()!

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

If anyone is interested in the maths / greedy approach for C. Here it is Submission.

I don't know why everyone is solving by dp when it can be solved with more ease.