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

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

279A - Point on Spiral

Из-за небольших ограничений в данной задаче можно было просто промоделировать шаги коня. Удобнее всего это делать, храня текущее направление движения и счетчик со значением, сколько шагов в эту сторону осталось. Заметим, что конь движется по спирали по следующему шаблону: 1 шаг вперед, поворот, 1 шаг вперед, поворот, 2 шага, поворот, 2 шага, поворот, 3 шага, поворот, 3 шага, поворот, 4 шага и так далее.

279B - Books

При решении этой задачи проще всего было воспользоваться методом двух указателей: левый указатель означает начало отрезка, правый — конец. При передвижении левого указателя на единицу вправо, правый надо двигать до тех пор, пока сумма ai внутри отрезка меньше или равна t. Так мы сможем для каждого левого конца найти максимально удаленный правый, а ответ на задачу — это максимальная длина из этих отрезков.

279C - Ladder

Давайте перед выполнением запросов выпишем в массив down отдельно все позиции i, для которых ai > ai + 1, и в массив up такие позиции i, такие что ai < ai + 1.

Теперь заметим важный факт для решения: отрезок [l, r] является лесенкой тогда, когда все позиции i, где ai < ai + 1 левее всех позиций j, в которых aj > aj + 1 (l ≤ i, j < r).

Для того, чтобы проверить это условие, давайте воспользуемся массивами up и down, в них с помощью бинарного поиска можно надо найти наибольший индекс i в отрезке, где происходит возрастание, и наименьший индекс j в отрезке, где происходит убывание, и если i < j, то отрезок — это лесенка. Отдельно необходимо рассмотреть случаи, когда числа в отрезке образуют невозрастающую или неубывающую последовательность.

279D - The Minimum Number of Variables

Давайте решать задачу методом динамического программирования по бинарной маске. Пусть текущее состояние — это mask. Через count(mask) обозначим количество единичных битов в маске, а через b1, b2, ..., bcount(mask) их индексы (здесь и далее будем использовать 0-нумерацию).

Наше состояние означает, что в данный момент у нас имеется count(mask) переменных, которые равны ab1, ab2, ..., abcount(mask). Будем считать, что дойдя до такого состояния, мы уже сумели произвести count(mask) операций, а значит, сейчас нам надо получить x = abcount(mask) + 1.

Если это число x не представимо в виде x = bi + bj, то тогда точно следующее значение мы получить не можем, и это состояние тупиковое, а иначе даже неважно какие именно значения i, j мы возьмем, главное — убедиться, что такие существуют.

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

В терминах масок первая операция выглядит как выкидывание одного из битов bk, и добавление нового бита, а вторая — просто добавление нового бита.

Начальное состояние в нашей динамике — это mask = 1, конечное — любая маска, в которой есть единичный бит на позиции n - 1 (в 0-нумерации).

При аккуратной реализации такое решение будет работать за O(2n·n). В частности, следующий хитрый прием поможет добиться этого: когда нам требуется проверить, что в маске есть такие два бита bi и bj, что acount(mask) = abi + abj, то будем использовать предподсчитанный массив diff[q][p], в котором будет записан индекс такого элемента массива a, который равен разности aqap.

Это позволит нам при проверке перебирать лишь значение bi.

279E - Beautiful Decomposition

Будет опубликовано чуть позже…

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

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

Можно подробнее B?

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

    проще показать сам код решения:

    int ans = 0, r = 0, sum = 0;
    forn(l, n) {
        while (r < n && sum + a[r] <= t) {
           sum += a[r];
           r++;
        }
    
        ans = max(ans, r - l);
        sum -= a[l];     
    }
    
    cout << ans << endl;
    
»
11 лет назад, # |
Rev. 5   Проголосовать: нравится 0 Проголосовать: не нравится

На B и C динамика простая. Одномерная

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

B можно и бинпоиском решить :)

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

ну очень понятно вот тут

Будем считать, что дойдя до такого состояния, мы уже сумели произвести count(mask) операций, а значит, сейчас нам надо получить x = acount(mask).

так все-таки, count(mask) — это количесто переменных или количество действий, которые мы произвели? ведь при присваивании мы можем какие-то биты удалить, и уже не будет count(mask) равно количеству действий, скорее уж количеству переменных, или я что-то не понял?

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

    Да, я немного ошибся.. Конечно же, у нас в маске каждый раз максимальный индекс единичного бита увеличивается ровно на единицу. Поэтому надо найти номер максимального единичного бита в маске, прибавить 1 и вот такое по счету число из массива a собирать.

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

опубликовали разбор? давайте его заминусуем! забавно.

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

В задаче "С" я обошелся без бинарного поиска. Идея была такова: 2 вспомогательных массива ll и lr. ll — для каждого i будем хранить самую правую позицию где заканчивается возрастающая часть лесенки из i. К примеру для массива a[] = {1, 2, 3, 1, 2}, ll = {2, 2, 2, 4, 4}. В lr тоже самое только наоборот — самая левая позиция убывающей части лесенки из i. В итоге ответом будет 'Yes', если ll[l] >= lr[r]. Сложность O(n + m)

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

Да, в С можно легко обойтись без логарифма. У меня решение чуть-чуть отличается от предложенных выше, хотя принцип тот же. Может, кому-нибудь мое будет понятнее :)

В up[i] храним начало подъема, на котором лежит i-ый элемент массива. В down[i] храним начало спуска, на котором лежит i-ый элемент массива. Понятно, как пересчитывать эти значения:

a[i] >= a[i — 1] -> up[i] = up[i — 1], иначе up[i] = i

a[i] <= a[i — 1] -> down[i] = down[i — 1], иначе down[i] = i

Получив запрос, мы можем посмотреть на следующее равенство: up[down[r]] = up[l]

То есть, если на отрезке есть "перелом", то он будет началом спуска для элемента r. Также начало подъема для "переломного" элемента должно быть таким же, как и для элемента l.

Осталось не забыть про случай, когда в запросе мы получили невозрастающую подпоследовательность, по условию она также будет являться "лесенкой". Этот случай обрабатывается равенством down[l] = down[r]

Случай с неубывающей подпоследовательностью автоматически обработается первым равенством.

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

Помогите найти ошибку в решении задачи C:

Пусть t[i] — количество "долин" на отрезке от 1 до i, т.е. кол-во таких i, что a[i]<a[i-1] и a[i]<a[i+1]. Тогда отрезок будет лесенкой, только если на отрезке [l+1; r-1] не будет "долин", т.е. t[r-1]-t[l]==0. Отдельно разбираем случаи l==r и l==r-1, но понятно, то тогда отрезок точно будет лесенкой.

Вердикт WA №19. На over10000-ной строчке выводит Yes вместо No. Во-первых понятно, что "долины" могут быть только на концах лесенки, а если они есть на отрезке [l+1; r-1], то отрезок точно не лесенка. (Или нет?!) Во-всяком случае, придумать пример, чтобы отрезок не был лесенкой, а мой вариант выводил, что он таковым является, я не смог.

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

Когда появится разбор задачи 279E - Красивая декомпозиция???

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

    Разбор в 0-индексации

    Идея 1:

    1. Нам не важно, приводить данное число к нулю или приводить ноль к данному числу сложениями/вычитаниями чисел вида 2^k;
    2. Рассмотрим двоичную запись числа от старших битов к младшим (ровно как в условии) тогда операция "прибавить 2^k" — это операция "занулить все единички слева до первого встречного нуля, а первый встречный ноль превратить в единичку", а операция "отнять 2^k" — это "заеденичить все нули слева до первой встречной единички, а первую встречную единичку превратить в ноль"
    3. Информацию "первая единичка слева от бита (i)" и "первый нолик слева от бита (i)" можно прекалкнуть.
    4. Пусть dpNull[i] — это количество прибавлений/вычитаний чисел вида 2^k которые нужны, чтобы занулить, число вида s[0..i-2]+"0" (простым языком — префикс длины i числа из условия, но на последнем месте этого префикса стоит 0), dpOne[i] — аналогичное, но на последнем месте стоит 1, и real(i) которая равна dpNull[i] еcли s[i]=='0' и dpOne[i] если s[i]=='1'

    С iым битом мы можем сделать три операции — оставить его в покое, прибавить ему 2^i и отнять от него 2^i, из всех этих вариантов нам нужно выбрать наилучший, собственно, пересчёт следующий:

    dpOne[i]=min(dpOne[Первый_ноль_слева(i)]+1,real(i-1)+1 ); Первый вариант — прибавить 2^i, второй — отнять, почему это так понятно из пункта 2, оставлять в покое смысла нету, так как тогда iый бит никогда не занулится.

    dpNull[i]=min(dpNull[Первая_единица_слева(i)]+1,real(i-1) ); Первый вариант — отнять 2^i, второй — оставить в покое, прибавлять смысла нету по тем же причинам.

    Ответ : real(s.size()-1);

    Так решал, например, я: 3253261

    Идея 2:

    Будем решать в числах n — число из задачи, k — степень двойки такая, что k/2<n<=k, то ответ на задачу, это 1 + ответ для min(k-n,n-k/2) вторая часть формулы — это просто вычитание старшего единичного бита, первая часть формулы — это, фактически, инверсия всех битов, которые не старше самой старшей единички. Фактически, мы просто работаем с самым старшим единичным блоком и решаем, как его выгодно занулить: инвертировав его в нули или вручную поотнимав. Работать можно, естественно, только со строками, и инверсию выполнять неявно (запомниать, сейчас инвертирована строка или нет).

    Так решал, например, Zip753: 3247041

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

      Вот еще довольно простое решение, как я понял жадностью.

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

    Скоро... :)

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

    Подобная задача была на Codeforces Beta Round #96. Div1 D "Константы на языке Шекспира". Разбор

    Можете пока прочитать тот разбор. Хотя там утверждается, что жадина не прокатит, я тем не менее сдал другой жадный алгоритм(3249333), и оно прошло все тесты.

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

Извиняемся за беспокойство, но как скоро будет "Оффициальный" разбор 279E - Красивая декомпозиция?

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

Could you please translate this editorial to english. Thanks.

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

can anyone help me to get where I am going wrong in my logic ? my code I am assuming : the answer is no only if there is a dip in the given range, eg. 2 1 3 has dip at index 1, also if query is in (1,2) then the subseg has no dip.

I am getting WA. any help would be great.

Edit: those who try this way, take into considerations of case like 2 1 1 2, as this is also dip but only for range (0,3) my accepted solution

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

    Hey, I know it's too late to make a difference for you but if you found a solution to this problem you encountered, could you please help me out to find the glitch in this algorithm because I am facing same issue as yours. Thanks in advance! :)

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

      Hey ! It has been 9 months, and I have completely forgot what this piece of code does. But I am sure the edit part in my comment, it solved my problem with the wa code.

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

https://codeforces.com/contest/279/submission/79049303 check this solution, using dp and no binary search

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

Can anybody explain 279E: Beautiful Decomposition?

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

I rather made a different states for dp in Problem C.

Let's call the value in ladder sequence such that  a[i]>=a[i+1] && a[i]>=a[i-1] as pivot. So for a index there are three possibility either before the pivot, pivot itself or after the pivot. We can use dp[3][n] representing all the three possibility respectively for all index where dp[j][i] stores the value of leftmost index of the ladder when ith index is having jth possibility. We than just have to check min(dp[0][r],min(dp[1][r], dp[2][r]))<=l for answer.

Link for solution — https://codeforces.com/contest/279/submission/85828747

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

I know it is late :/ .Can someone explain what is the mistake in my code for problem C? Here is the link to my submission. https://codeforces.com/contest/279/submission/90775068

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

101232184 simple solution for C, just about finding peaks

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

can somebody plz translate problemB explanation to english

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

    279B — Books — When solving this problem, it was easiest to use the method of two pointers: the left pointer means the beginning of the segment, the right one — the end. When moving the left pointer one unit to the right, the right one must be moved until the sum a i inside the segment is less than or equal to t . This way we can find for each left end the most distant right end, and the answer to the problem is the maximum length of these segments.