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

Автор FairyWinx, 2 месяца назад, По-русски

Задача A.

Решение

Задача B.

Решение

Задача C.

Решение

Задача D.

Решение

Задача E.

Решение

Задача F.

Решение

Полный текст и комментарии »

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

Автор FairyWinx, 2 месяца назад, По-русски

Neko Nya, Кодефорсес =^● ⋏ ●^=

Я рад пригласить вас поучаствовать в Codeforces Round 926 (Div. 2). Он состоится в 15.02.2024 17:35 (Московское время) и в нем вы будете помогать мальчику Саше добиться девочки. Раунд будет рейтинговым для всех участников с рейтингом строго меньшим 2100. И у вас будет 2 часа, чтобы решить 6 задач.

Тута благодарность всем соучаствуюшим в раунде:

Жду всех на раунде >~<

UPD: Разбалловка: 500 — 1000 — 1500 — 2000 — 2500 — 3000

UPD2: Разбор

Полный текст и комментарии »

  • Проголосовать: нравится
  • +686
  • Проголосовать: не нравится

Автор FairyWinx, история, 20 месяцев назад, По-русски

Задача A. Идея Igorbunov

Hint 1
Решение

Задача B. Идея FairyWinx

Hint 1
Hint 2
Hint 3
Hint 4
Решение

Задача C. Идея FairyWinx

Hint 1
Hint 2
Hint 3
Решение

Задача D. Идея FairyWinx

Hint 1
Hint 2
Решение

Задача E. Идея FairyWinx

Hint 1
Hint 2
Hint 3
Решение

Задача F. Идея TeaTime

Пока разбор доступен в английской версии. Перевод появится скоро (или не очень).

Полный текст и комментарии »

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

Автор FairyWinx, история, 20 месяцев назад, перевод, По-английски

Приветствую, Кодефорсес ✿*∗˵╰༼✪ᗜ✪༽╯˵∗*✿

(Welcome, Codeforces on Russian)

TeaTime and I are happy to invite you to participate in Codeforces Round 818 (Div. 2). It will take place on 02.09.2022 17:35 (Московское время). The round will be rated for all participants with rating strictly lower than 2100. You will have 2 hours to solve 6 problems.

The standard place for thanks:

See you at the round🥰

Scoring distribution: 500 — 1000 — 1500 — 2000 — 2000 — 3000

UPD: Editorial!!! (Thanks to purplesyringa for English translation)

UPD: Winners!

Div 2:

Div 1:

Полный текст и комментарии »

  • Проголосовать: нравится
  • +466
  • Проголосовать: не нравится

Автор FairyWinx, 23 месяца назад, По-русски

Дана следующая задача: дан массив целых чисел $$$a_1, \ldots, a_n$$$, а также $$$q$$$ запросов одного из двух видов:

  1. $$$a_i += x$$$, где $$$l \leq i \leq r$$$.
  2. узнать количество индексов $$$i$$$, где $$$l \leq i \leq r$$$ и $$$a_j < a_i$$$, для всех $$$j:$$$ $$$l \leq j < i$$$. (Или по-человчески — количество префиксных максимумов на отрезке)

Очень хочется это решать быстрее, чем за $$$O(sqrt(n))$$$ на запрос.

Рассмотрим более легкий вариант, когда у нас нет запросов изменения. Тогда можно просто сделать Дерево отрезков, где в вершине хранится отсортированный список префиксных максимумов, если наш отрезок — это отрезок, соответствующий вершине дерева отрезков. Тогда мы должны просто сделать алгоритм, анологичный Merge Sort Tree, только мы должны в запросе вершины, на которые мы разбиваем разбиваем запрос, рассматривать слева направо и хранить максимум среди предыдущих элементов на подходящем отрезке, и к ответу прибавлять количество элементов в вершине, больших максимума до этого, а затем обновить максимум.

Это работает за $$$O(log(n)^2)$$$ на запрос, а также $$$O(nlog(n))$$$ памяти и времени на построение.


Заметим, что это можно переделать, чтобы были запросы изменения. Тогда нам нужно только научиться объединять такие списки и прибавлять к ним значение. А для этого подходит, например, персистентное декартво дерево. Тогда мы в вершине будем хранить персистентное декартово дерево из всех префиксных максимумов. Тогда при обновлении, если отрезок вершины лежит полностью внутри запроса, то просто добавим в наше декартово дерево нужное значение (ну и понятное дело, пропушим вниз это значение). А для объединения списков нужно просто скопировать значения из левого поддерева, а также выбрать нужный суффикс из правого поддерева и его также скопировать, а затем объеденить эти деревья.

Это уже работает за $$$O(log(n)^2)$$$ на запрос, но в этом случае будет построение за $$$O(nlog(n)^2)$$$, а, что самое главное, памяти будет $$$O((n + q)log(n)^2)$$$ суммарно, что пихать, конечно же, не очень хочется.


Теперь нормальное решение за $$$O(n)$$$ памяти и $$$O(log(n)^2)$$$ на запрос.

Пусть есть самое обычное дерево отрезок (У вершины $$$v$$$ есть левое поддерево — это $$$v.l$$$, а правое — это $$$v.r$$$), тогда пусть, мы для каждой вершины $$$v$$$ научились считать две величины $$$cnt_v$$$ — количество префиксных максимумов, если наш отрезок — это отрезок соответствующий вершине $$$v$$$, и $$$max_v$$$ — это максимум на том же отрезке.

Тогда реализуем функцию $$$f(v, x)$$$, которая будет считать количество префиксных максимумов строго больших $$$x$$$ на отреке вершины $$$v$$$.

У нас есть всего три случая:

  1. Если $$$v$$$ — это лист, то все просто, нужно сравнить значение у этого элемента с $$$x$$$.
  2. Если $$$x \geq max_{v.l}$$$, тогда заметим, что в левом поддереве нет точно подходящих элементов (так как они меньше или равны $$$x$$$), тогда нам интересно только правое поддерево, то есть $$$f(v, x) = f(v.r, x)$$$.
  3. Если $$$x < max_{v.l}$$$, тогда нам уже не интересно значение $$$f(v.r, x)$$$, так как элемент со значением $$$max_{v.l}$$$ точно будет среди префиксных максимумов, значит количество префиксных максимумов справа будет такое же, как и в случае отсутствия ограничения на $$$x$$$, а это количество мы уже знаем — это $$$cnt_v - cnt_{v.l}$$$, так как нам нужно количество максимумов справа, а это все, кроме тех, кто слева (логично, не правда-ли) (и это не $$$cnt_{v.l}$$$, так как в этом случае могут быть элементы меньше $$$max_{v.l}$$$). Значит $$$f(v, x) = f(v.l, x) + cnt_v - cnt_{v.l}$$$.

Эта функция работает за $$$O(log(n))$$$, так как каждый раз мы спускаемся ровно в одно поддерева, а глубина дерева отрезков как раз логарифм.

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

Реализация

Также спасибо Um_nik, который, собственно, придумал последнее решение в задаче, которая сводилась к этому и сделал ее значительно интереснее)))

А также примеры задач на эту технику 1, 2.

Полный текст и комментарии »

  • Проголосовать: нравится
  • +140
  • Проголосовать: не нравится

Автор FairyWinx, 2 года назад, По-русски

Задача A. Идея FairyWinx

Подсказка 1
Подсказка 2
Решение
Реализация

Задача B. Идея FairyWinx

Подсказка 1
Подсказка 2
Решение
Реализация

Задача C. Идея FairyWinx

Подсказка 1
Подсказка 1
Подсказка 2
Решение
Реализация

Задача D. Идея FairyWinx

Важный факт
Подсказка 1.1
Подсказка 1.2
Подсказка 1.3
Решение 1
Реализация
Подсказка 2.1
Решение 2 (которое писали почти все)
Реализация

Задача E. Идея FairyWinx

Подсказка 1
Подсказка 2
Подсказка 3
Подсказка 4
Подсказка 5
Решение
Реализация

Задача F. Идея Igorbunov

Подсказка 1
Подсказка 2
Подсказка 3
Подсказка 4
Подсказка 5
Решение
Реализация

Полный текст и комментарии »

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

Автор FairyWinx, 2 года назад, По-русски

Привки, Кодефорсес (ノ◕ヮ◕)ノ*:・゚✧

Igorbunov и я рады пригласить вас поучаствовать в Codeforces Round 777 (Div. 2) (шутка про казино), все задачи которого будут про маленькую девочку Мадоку. Он состоится в 11.03.2022 17:35 (Московское время). Раунд будет рейтинговым для всех участников с рейтингом строго меньшим 2100. И у вас будет 2 часа, чтобы решить 6 задач.

Также хочется выразить благодарность следующим лицам:

Желаю высокого рейтинга, а также надеюсь, что я помогу вам хоть на немного отвлечься от не самых лучших новостей (❤ω❤)

Разбалловка: 500 — 1250 — 1500 — 2000 — 2500 — 3000

UPD1: Разбор на русском

UPD2: Поздравим победителей контеста

Div 1+2

1 jqdai0815 9457
2 Geothermal 9219
3 rainboy 8649
4 End. 8529
5 kshitij_sodani 8250

Div 2

1 shnirelman 6955
2 zzfzzfzzfzzf 6558
3 Kaname-Madoka 6539
4 peuch 6317
5 rsy 6301

Полный текст и комментарии »

  • Проголосовать: нравится
  • +808
  • Проголосовать: не нравится

Автор FairyWinx, история, 3 года назад, По-русски

Пусть нам очень хочется решить следующую задачку:

Дано дерево и поступают два вида запросов — добавить X на пути, посчитать минимум вне пути. И требуется отвечать на каждый запрос за $$$O(n \cdot log^2n)$$$

Решение курильщика: Давайте сделаем HLD декомпозицию, и для каждого пути будет также хранить его id и минимум в нем. И будем хранить эти величины в множестве. Тогда запрос на добавление на пути — просто делаем стандартное обновление на пути в HLD, изменяя значения в множестве. Запрос минимума уже более интеллектуальный, посмотрим, на какие пути он разбивается, и выкинем их из множества (если путь входит частично, то мы только конец пути будем учитывать в ответе, и также будем выкидывать путь из множества). А ответ — минимум из этой величины и минимума в множестве. Так как все пути в множестве нам подходят. А ничего лишнего мы также не учли. Затем все откатываем и радуемся жизни.

Нормальное решение: Давайте просто сделаем HLD Вадомара (то бишь HLD, у которого можно спрашивать про поддеревья). И запрос изменения — обычный update в HLD, а чтобы получить ответ просто присвоим бесконечность на пути, и возьмем минимум.

Скорее всего многие это знали, но как по мне все равно забавно.

Полный текст и комментарии »

Теги hld
  • Проголосовать: нравится
  • +28
  • Проголосовать: не нравится

Автор FairyWinx, 3 года назад, По-русски

Решим следующую задачу: Требуется уметь находить произведение чисел на отрезке по модулю, а также умножать все числа на отрезке на некое число x на отрезке. И все по модулю

Понятно, что это решается обычным деревом отрезков с отложенными массовыми операциями. Но в этом случае мы при каждом вызове функции get и update будем пушить значения в детей, что очень долго (У нас в этом случае будет 4 умножения по модулю в функции push). Давайте научимся делать массовые операции не проталкивая значения в детей.

Утверждение, такой код работает (там есть беды с переполнением, но это остается, как упражнение читателю):

Функция update:

void update(int v, int l, int r, int L, int R, int val) {
    if (R <= l || r <= L)
        return;
    if (L <= l && r <= R) {
        t[v] = (t[v] * pow(val, (r - l))) % MOD;
        mod[v] = (mod[v] * val) % MOD;
        return;
    }

    int m = (l + r) / 2;
    update(v * 2 + 1, l, m, L, R, val);
    update(v * 2, m, r, L, R, val);
    t[v] = t[v * 2 + 1] * t[v * 2] * pow(mod[v], (r - l)) % MOD;
}

Функция get:

int get(int v, int l, int r, int L, int R) {
    if (R <= l || r <= L)
        return 1;
    if (L <= l && r <= R)
        return t[v];

    int m = (l + r) / 2;
    return get(v * 2 + 1, l, m, L, R) * get(v * 2, m, r, L, R) * pow(mod[v], max(L, l) - min(R, r)) % MOD;
}

Почему это так: понятно, что в вершине корректное значение, если мы не смотрим на обновления, которые были сверху. (По аналогии с обычным деревом отрезков). Ну а верхние обновления мы учтем, когда будем спускаться в функции get.

Брать модуль у числа не самое быстрое занятие, поэтому функция push в ДО работает очень долго, и такой способ написания ДО очень сильно ускоряет код (когда я пихал корнячку с таким ДО (ну и там не только операции с ДО были) время с 8 секунд уменьшилось до 6, что очень и очень существенно) Ну и это также работает с минимумом/максимумом/суммой и многими другими функциями, и работает быстрее. Такие вот пироги

Полный текст и комментарии »

  • Проголосовать: нравится
  • +41
  • Проголосовать: не нравится

Автор FairyWinx, история, 3 года назад, По-английски

Fun fact one: Another account can liked comment in draft block, and it will get contribution.

Fun fact two: in one-two hour considred real contribution on comment/post from like.

And i'm conducted an experiment: call different color, and we put like on comment. And now i can tell: Blue get 3 contribution. Purple get 5 contribution. Yellow (2100-2299) get 8 contribution. Red (2400-2599) get 10 contribution. I don't know, this considered from now rating or max rating, and i don't get information for another color.

Полный текст и комментарии »

  • Проголосовать: нравится
  • +223
  • Проголосовать: не нравится

Автор FairyWinx, история, 4 года назад, По-русски

Кто-нибудь знает, почему CF показывает вердикты у неправильных попыток в десятки раз дольше, чем у правильных? Ведь это нелогично, оно протестировалось на меньшем количестве тестов, но вердикт давать не хочет.

Полный текст и комментарии »

  • Проголосовать: нравится
  • +8
  • Проголосовать: не нравится